home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Manuels & Misc / Assembly / AOA.ZIP / CH13 / EX13_1.IN < prev    next >
Encoding:
Text File  |  1996-02-24  |  335.7 KB  |  10,278 lines

  1. ***************************************************************************
  2. ***************************************************************************
  3.  
  4.  
  5.  
  6. The UCR Standard Library for Assembly Language Programmers,
  7. Written By Randall Hyde and others, is
  8.  
  9.   sssssss      ss     ss       ss       sssssss     sssssss
  10.   ss           ss     ss      ssss      ss    ss    ss
  11.   ss           ss     ss     ss  ss     ss    ss    ss
  12.   sssssss      sssssssss    ssssssss    sssssss     sssss        ssssssss
  13.        ss      ss     ss    ss    ss    ss  ss      ss
  14.        ss      ss     ss    ss    ss    ss   ss     ss
  15.   sssssss      ss     ss    ss    ss    ss    ss    sssssss
  16.  
  17.  
  18.  
  19.   ww                  ww       ww       sssssss     sssssss
  20.    ww                ww       wwww      ss    ss    ss
  21.     ww      ww      ww       ww  ww     ss    ss    ss
  22.      ww    wwww    ww       wwwwwwww    sssssss     sssss
  23.       ww  ww  ww  ww        ww    ww    ss  ss      ss
  24.        wwww    wwww         ww    ww    ss   ss     ss
  25.         ww      ww          ww    ww    ss    ss    sssssss
  26.  
  27.  
  28.  
  29.  
  30. We do not want any registration fees for this software.
  31.  
  32. Now for the catch...  It is more blessed to give than to receive.  
  33. If this software saves you time and effort and you enjoy using it, 
  34. our lives will be enriched knowing that others have appreciated our work.  
  35. We would like to share this wonderful feeling with you.  If you like this 
  36. software and use it, we would like you to contribute at least one routine to 
  37. the library.  Perhaps you think this library has some neat-o routines in it.  
  38. Imagine how nice it would become if everyone used their imagination to 
  39. contribute something useful to it.
  40.  
  41. We hereby release this software to the public domain.  You can use it in any
  42. way you see fit.  However, we would appreciate it if you share this software 
  43. with others as much as it has been shared it with you.  That is not to suggest
  44. that you give away software you have written with this package (We're not 
  45. quite as crazy as Richard Stallman, bless his heart), but if someone else would 
  46. like a copy of this library, please help them out.  Naturally, we would be 
  47. tickeled pink to receive credit in software that uses these routines (which is 
  48. the honorable thing to do) but we understand the way many corporations operate 
  49. and won't be terribly put off if you use it without giving due credit.  
  50.  
  51. Enjoy!
  52.  
  53. If you have comments, bug reports, new code to contribute, etc., you can 
  54. reach us through (address and email are circa 1993, if you read this in
  55. 1999, don't count on it!):
  56.  
  57.         rhyde@cs.ucr.edu        (On Internet).
  58.  
  59. or
  60.  
  61.         Randall Hyde
  62.         Dept of Computer Science
  63.         100 University Office Bldg
  64.         University of California
  65.         Riverside, Ca. 92521
  66.  
  67.  
  68. COMMENTS ABOUT THE CODE:
  69. ************************
  70.  
  71. Please don't expect super optimal code here.  Most of it is fairly mediocre
  72. (from a size/speed point of view).  Hopefully, you'll agree, it's the idea
  73. that counts.  If you do not like something I have done, you have got the
  74. sources -- have at it.  (Of course, it would be appreciated if you would
  75. send any modifications to one of the E-MAIL addresses above.)
  76.  
  77.  
  78. ****************+******************** NOTE ************************************
  79.  
  80. Please understand the purpose of this code!  This library is here to make
  81. assembly language programming easy.  The nature of this library encourages
  82. people to write code in a fashion similar to that employed when they write
  83. programs in a high level language like C.  While this familiar style of
  84. programming does make the task easier, it is not the most appropriate
  85. approach to use when flat-out performance is what you're seeking.  "C code
  86. written with MOV instructions" is never as fast as pure assembly language
  87. code employing the proper programming paradigm.  Why mention this?  Well,
  88. some readers may have heard about assembly language's legendary performance
  89. and they're expecting to achieve that using this library.  While programs
  90. written with this library may very well run faster than a comparable program
  91. written in a HLL, you will not get fantastic performance improvement until
  92. you stop thinking in HLLs and starting "thinking" in assembly.  The purpose
  93. of this library is to help you *avoid* thinking in assembly language.  There-
  94. fore, this code will not help you achieve those fantastic performance levels
  95. you've been hearing about; indeed, this library may stand in the way of that
  96. goal.  It's not that these routines are terribly slow, mind you.  They just
  97. encourage an inappropriate programming style if speed is what you're after.
  98.  
  99. On the other hand, since only 10-20% of the code of any given program
  100. represents the time critical stuff (an argument long employed by HLL
  101. supporters), there is nothing wrong with judicious use of this code within
  102. a program that has to be fast.  As usual, if performance is your primary
  103. goal, you must study the problem and the program you generate very carefully
  104. to isolate the time critical portions.  If you are interested in high-
  105. performance programming at the "micro-algorithm" level, you should take a look
  106. at Michael Abrash's text "Zen of Assembly."  This excellent book will explain
  107. many ways to improve the performance of your code at the sub-algorithm level
  108. (where assembly language really shines).
  109.  
  110.  
  111.  
  112. COMMENTS ABOUT THIS DOCUMENTATION:
  113. **********************************
  114.  
  115. You will have to forgive us for the inconsistent style appearing throughout
  116. this document.  Keep in mind that this document has been prepared by many
  117. different people.  Keeping the styles consistent is a time consuming and
  118. difficult task.
  119.  
  120. Whenever a routine's description claims that the flags are not affected,
  121. you should not interpret this to mean that the routine preserves the flags.
  122. Most routines do *not* preserve any of the flags.  Such a statement simply
  123. means that the routine does not *explicitly* return a value in one (or more)
  124. of the flag bits.
  125.  
  126. Note that proper credit has been given to the author of each of the various
  127. routines appearing in this library *except* for many written by Randall
  128. Hyde.  All routines without an author by-line were probably written by
  129. Randall Hyde (unless we screwed up somewhere and forgot to put a name
  130. in the documentation).  Most of these routines were tested and documented
  131. by various students in Randy Hyde's CS 13 (assembly language) and CS 191X /
  132. CS 185 courses (Commercial Software Development).  There are too many names
  133. to mention here, but these students definitely deserve the credit for locating
  134. numerous bugs in the code, providing many suggestions, and doing other work.
  135.  
  136. Of course, there have been numerous suggestions and bug notices from helpful
  137. souls on BIX and the Internet, as well.  Thank you all.
  138.  
  139. *NOTICE* We have noticed, from time to time, that there are routines in the
  140. library which have not been documented.  Perusing the source listings will
  141. help you locate some library routines which have slipped through the cracks.
  142. Also keep in mind that there isn't a one to one correspondence between
  143. source files and library routines.  Many of the source files contain
  144. two or more library routines.  Someday we will attempt to document which
  145. files contain which routines, but that's in the future for now.
  146.  
  147. =============================================================================
  148.  
  149. Version History:
  150.  
  151. Version 00-     Initial release as "Randy Hyde's Standard Library for 80x86
  152.         Assembly Language programmers"
  153.  
  154. Version 10-    Initial release as "UCR Standard Library..."  CS 191X
  155.         students did some testing and documentation in this release.
  156.  
  157. Version 20-    More testing on several routines.  Added floating point
  158.         library and several other routines.
  159.  
  160. Version 21-    Fixed *MAJOR* bugs in floating point package.  Added
  161. 11-1-91        several new routines.  Included new "TEST" files with
  162.         the library.  Also included SHELL.ASM file inadvertently
  163.         left out of Version 2.0.
  164.  
  165. Version 22-    Made some minor modifications to puth, putl, ltoa, and htoa
  166. 11-14-91    as per suggestions made by David Holm and Terje Maithesen
  167.  
  168. Version 23-    Made a small but *major* modification to the stdlib.a and
  169. 11-22-91    stdlib.a6 files to force library calls into the STDGRP group.
  170.         Otherwise the linker substitued bad segment addresses for
  171.         the far calls to the library routines.  A real problem when
  172.         accessing variables in StdData.
  173.  
  174. Version 24-    Yet more changes to fix the stupid MASM group/segment:offset
  175. 12-7-91        bug.  Made various changes to the STDLIB.A file.  Also fixed
  176.         a problem in the FP routines- forgot to declare sl_sefpa
  177.         public.  Finally, created batch file to automatically unpack
  178.         everything from DOS (assuming presence of PKUNZIP somewhere
  179.         in the current path).
  180.  
  181. Version 25-    Some new macros (DOS, ExitPgm), fixed a problem with the
  182. 12-25-91    PUTI routine, added some SmartArray items.  Also added the
  183.         GetEnv routine.
  184.  
  185. Version 26-    Maintenance release coinciding with the Dr. Dobb's article
  186. 2/20/92        in the March 1992 issue.
  187.  
  188. Version 27-    SmartLists and interrupt driven serial routines added to
  189. 6/19/92        the libraries.  Also created smaller include files for
  190.         each of the standard library categories. (note: the serial
  191.         routines actually existed prior to this release, they were
  192.         cleaned up and documented for this release).  Fixed a couple
  193.         of truly disgusting bugs in the floating point package
  194.         (wouldn't properly print values like 8100 and hung whenever
  195.         encountering a zero value in FADD/FSUB).
  196.  
  197. Version 28-    Modified MemInit to allow the programmer to specify how many
  198. 8/20/92        pages to reserve for the heap and the location of the heap.
  199.  
  200. Version 29-    Added HeapStart routine to the memory management code so an
  201. 10/5/92        application could get the segment address of the start of
  202.         the heap.  This is useful when you want to deallocate the
  203.         heap (by calling DOS' deallocate routine), for example, to
  204.         free up the heap memory so you can run another application.
  205.         What really needs to be done here is to write a dealloc
  206.         routine, but HeapStart offered some flexibility.
  207.  
  208. Version 30-    Fixed bug in ATOH2 routine (it incremented DI once too far).
  209. 10/11/92-    Also fixed the same bug in ATOI2, ATOU2, ATOL2, ATOUL2, etc.
  210. 3/16/93        Added StrTrim (m) and StrBlkDel (m) to the library.  Added
  211.         the pattern matching package to the library. Added the date
  212.         and time routines (ATOD, DTOA, DTOA2, DTOAm xDTOA, xDTOAm,
  213.         xDTOA2, ATOT, TTOA, TTOA2, TTOAm xTTOA, xTTOAm xTTOA2) to
  214.         the library.  Fixed a bug in ATOI and ATOL which passed off
  215.         the ":" character as a numeric digit.  Broke the MemInit
  216.         routine into two separate routines: MemInit & MemInit2 which
  217.         let the user specify the location of the heap or use all the
  218.         available memory.  Also, no longer require that PSP be a
  219.         global variable (However, the library does require DOS 3.3
  220.         or later).  Fixed a bug in PRINTF/PRINTFF (it did not
  221.         properly restore the flags and BP). Fixed a bug in the
  222.         LSFPO routine (thanks to Tim Farley for pointing this out).
  223.         Added the process manager package to the library.
  224.  
  225. Version 31-    Fixed a bug in strstr which prevented it from matching a
  226. 6/10/93        substring at the beginning of a string.  Added file
  227. 7/24/93        routines to the library.  Added macros for strbdel and
  228. 8/1/93        strtrim to string.a.  Fixed a bug in stricmpl, forgot to
  229.         copy a pointer into SI within the routine.  Fixed a bug in
  230.         CPUID which crashed the machine if a 486.
  231.  
  232. Version 32-    Fixed several bugs in the list routines.  Added some actual
  233. 3/24/94        file routines to the library.  Updated the documentation.
  234.  
  235. Version 33-    Fixed some bugs in the floating point code.  Fixed a bug
  236. 7/15/94        a bug in the pattern matching code.  Added new pattern
  237.         match routines.  Changed the name of CPUID because it
  238.         conflicts with the Pentium instrucion of the same name.
  239.         Fixed several bugs in the processes package.  Fixed some
  240.         problems in the documentation (certain routines were listed
  241.         by the wrong name).
  242.  
  243. Version 34-    Fixed several problems in the documentation.  Some other
  244. 11/18/94    minor bug fixes including changing the CPUID name to
  245.         CPUIDENT (to avoid conflict with Pentium CPUID instruction).
  246.         Also modified IBML to use CPUIDENT rather than CPUID.
  247.  
  248. Version 35-    Fixed a problem with a signed comparison in the pattern
  249.         matching code.  It turned out that if you failed on the
  250.         first character of a string, it bombed the system.  Also
  251.         changed the doc on patterns to fix an error.
  252.  
  253. Version 36-    Fixed a bug in the FREAD routine.  There are known bugs in
  254. 4/4/95        the floating point package, but cannot get a sample example
  255.         to determine cause.
  256.  
  257. ==============================================================================
  258.  
  259.  
  260. ROUTINES WE WOULD LIKE TO HAVE:
  261. *******************************
  262.  
  263. If you're interested in adding some routines to this
  264. package, GREAT!  Here are some suggestions.
  265.  
  266. 1) Routines which manipulate directories (read/write/etc.)
  267. 2) We did it already!
  268. 3) Length-prefixed strings package.
  269. 4) A graphics package.
  270. 5) An object-oriented programming class library.
  271. 6) Floating point functions (e.g., SIN, COS, etc.)
  272. 7) Just about anything else appearing in a HLL "standard" library.
  273. If you've got any ideas, we would  love to discuss them with you.  The best
  274. way to reach us is through the E-MAIL addresses above.
  275.  
  276.  
  277. MISSING ROUTINES TO BE SUPPLIED IN THE FUTURE:
  278. **********************************************
  279.  
  280.  
  281.     Table Package
  282. TblInit-    Initializes a particular table.
  283. TblEnter-    Enters an item into a table.
  284. TblLookup-    Looks up an item in a table.
  285. TblFree-    Free up memory in use by a table.
  286.  
  287.     Tree Package
  288. <pretty much the same routines as the list package>
  289.  
  290.     Set Package
  291. <Generic set routines (not just character set routines) similar to cset pkg>
  292.  
  293.  
  294.     Processes Package
  295. Sleep-        Delays a process for some period of time.
  296. YieldTo-    Transfers control to a specific process.
  297. Forkm-        Allocates new PCB on the heap.
  298. Sync-        Halts a process until another process dies.
  299. Join-        Merges two processes together.
  300. wait & release-    Semaphore/synchronization primitives.
  301.  
  302.  
  303.     80386 Optimized Code
  304. Despite the disclaimer about speed earlier in this document, we do have
  305. plans to rewrite this routine for speed at some point in the future.
  306. At that time we will write the code specifically for 80386 and later
  307. processors (the code will probably be optimized for Pentium/586 processors
  308. at that time).  Stay tuned.
  309.  
  310.  
  311. HOW TO USE THE STANDARD LIBRARY:
  312. ********************************
  313.  
  314. When you are ready to begin programming with the library, you should
  315. copy the shell.asm file, provided in the package, to another file in
  316. which you will be working, i.e. myprog.asm.  The shell.asm file sets
  317. up the machine (segments, etc.) as the UCR Standard Library expects
  318. them.  Results are undefined for other setups.  Therefore, I strongly
  319. suggest, that when you begin using these routines, you follow the
  320. shell.asm format.  Later, when you are familiar with the software,
  321. you may wish to create your own shell.asm file, but it is wise to
  322. initially use the one provided.  The shell.asm file has comments which
  323. tell you where to place your code, variables, etc.
  324.  
  325. There is an include file stdlib.a which
  326. you should include in every assembly you perform which calls the stdlib
  327. routines.  SHELL.ASM already includes this file.  *YOU MUST PLACE THE
  328. INCLUDE STATEMENT OUTSIDE OF ANY SEGMENTS IN YOUR PROGRAM*.  Preferably
  329. as the first line of your program (just like SHELL.ASM).  If you place
  330. this include directive inside a segment, certain assemblers/linkers
  331. (especially MASM) will not properly assemble and link your programs.
  332. They will assemble and link without error, but the resulting program
  333. will not execute correctly.
  334.  
  335. The STDLIB.A file contains macros you can use to call each of the routines
  336. in the standard library.  For example, to call PRINTF you would use the
  337. statement
  338.         printf
  339.         db    "format string",0
  340.         db    other,vars
  341.  
  342. rather than "calling" printf.  Printf is actually a macro, you cannot call
  343. it directly (all of the standard library routines have names like "sl_printf"
  344. and the macro issues a call to the appropriate routine).  These macros have
  345. two main purposes-- first, the differentiate calls to the standard library
  346. routines (i.e., no "call" instruction is the difference); and second, they
  347. contain some extra code to perform "smart linking" with MASM 5.1 & earlier,
  348. TASM, and OPTASM.  MASM 6.0 supports a new directive, extrndef, which
  349. eliminates the need for this extra code, but the extra code works nonetheless.
  350.  
  351. Starting with version 27, many of the standard library macros were separated
  352. into smaller files.  This speeds up assembly when you don't need *all* of
  353. the routines in the library (the macro file is getting quite large).
  354. STDLIB.A still exists and still loads everything, but you should get in the
  355. habit of specifying the smaller files instead.  For MASM 6.0 users, a
  356. special set of include files "*.a6" are now available.  MASM 6.0 seems to
  357. run out of memory if you include "stdlib.a6" (which includes everything) so
  358. you may have to include only those files you actually use.
  359.  
  360.  
  361. All of the standard library routines, and most of their local data values,
  362. are in a segment named "stdlib".  You should not create such a segment unless
  363. you plan on adding new routines to the standard library.
  364.  
  365.  
  366. Note:     if you want to use the pattern matching functions provided in the
  367.     pattern matching package, you will need to include the following
  368.     statement somewhere *after* the "include stdlib.a" or
  369.     "include pattern.a" statement:
  370.  
  371.             matchfunc
  372.  
  373.     This declares the necessary external names required by the pattern
  374.     matching operations.  The SHELL.ASM file contains a commented-out
  375.     line with this statement.  If you use pattern matching in programs
  376.     which start out as SHELL.ASM you can simply uncomment this line.
  377.  
  378.  
  379.  
  380. HOW THE STANDARD LIBRARY IS ORGANIZED:
  381. **************************************
  382.  
  383. The documentation spec sheets for each of the standard library routines appear
  384. in other files provided with the standard library.  We've organized these
  385. routines by category.  The categories supported to date include
  386.  
  387.     Standard Input Routines
  388.     Standard Output Routines
  389.     Conversion Routines
  390.     Utility Routines
  391.     String Handling Routines
  392.     Memory Management Routines
  393.     Character Set Routines
  394.     Floating Point Routines
  395.     File I/O
  396.     Miscellaneous Routines
  397.     Time & Date Routines
  398.     Smart List Routines
  399.     Serial Port I/O
  400.     Pattern Matching Package
  401.     Process Package
  402.  
  403.  
  404.  
  405. IF YOU WANT TO PLAY WITH THE SOURCE LISTINGS
  406. ********************************************
  407.  
  408. Most users will probably use the standard library routines in object form
  409. and never worry about the actual implementation.  If you, on the other hand,
  410. want to get "under the hood" and take a look at how this code was written
  411. (perhaps to fix a bug), all the source listings are provided with this
  412. release.
  413.  
  414. We assemble the library for final distribution using TASM 3.0 with the
  415. "/M3",  "/jjumps", and "/ic:\stdlib\include" command line options.  If you
  416. do not specify these options you will probably get an assembly error.
  417.  
  418. All initial development of these routines was done with MASM.  By writing the
  419. code with MASM and then assembling the final release version with TASM we
  420. could verify that the code worked with both assemblers.
  421.  
  422. That is, at least, until MASM 6.0 came along.  All new routines written since
  423. the introduction of MASM 6.0 were developed with MASM 6.0 and assembled with
  424. TASM 3.0.  They should compile with MASM 5.1 as well (though we haven't
  425. verified this).  HOWEVER, older routines written before the release of MASM 6
  426. will probably not assemble properly under MASM 6.0 unless you specify the
  427. MASM 5.1 compatibility options.  Furthermore, routines written after the
  428. release of MASM 6.0 take advantage of MASM/TASM's "branch out of range"
  429. automatic correction and may produce errors when assembled under MASM 5.1.
  430.  
  431. Moral of the story-- If you're still using MASM 5.1 (or earlier) or TASM 2.0
  432. (or earlier), *upgrade*!
  433.  
  434. Given the divergent paths that MASM 6.0 and TASM 3.0 are taking, it is
  435. unlikely that we will continue to provide all future code in a form which
  436. compiles under both assemblers.  The windowing package we've created (but
  437. have not released), for example, will only assemble under MASM 6.0.  We will
  438. always make sure that the object code works with any assembler/linker out
  439. there, but it's unlikely we will continue to support both MASM and TASM
  440. at the source level for TASM indefinitely (unless BORLAND gives us good
  441. reason to do otherwise, like having a MASM 6.x compatibility mode).  Sorry,
  442. it's just too much work for so little return.
  443.  
  444. Of course, if you would volunteer to translate our MASM 6 code to TASM,
  445. we'd be more than happy to give you full credit for your work.
  446.  
  447. Currently (6/93), MASM 6.0 and MASM 6.1 have some severe bugs which create
  448. some major problems.  As soon as a stable release appears we will convert
  449. specifically to MASM 6.x.
  450.  
  451. Acknowledgements
  452. ================
  453.  
  454. There are far too many people who have their fingers in this package to
  455. give full credit to everyone involved.  Futhermore, this section was
  456. added long after many hard-working people's efforts were forgotten.
  457. If you are one of these people, send me (rhyde) email and I will
  458. certainly rectify this situation.
  459.  
  460. Most of the routines in the library were written by Randy Hyde.
  461. Those routines authored by someone else contain appropriate notes in the
  462. comments found in the source listing.
  463.  
  464. Many thanks to those who have found problems in routines in the library.
  465. This includes the students in CS 191x, CS 185, CS 162ABC, and CS 13 at
  466. UC Riverside.  They have made important contributions to this library
  467. and their efforts are not forgotten.
  468.  
  469. Special thanks to the CS 191x class at UC Riverside who reorganized the
  470. documentation from its original sorry state.  Special thanks to Steve
  471. Shah for his quick reference guide.
  472.  
  473. Last, but certainly not least, praise and glory to our Lord for giving us
  474. all the talent to achieve this...
  475.  
  476. In the future, I will endeavor to keep this section up to date and provide
  477. personal acknowledgements to those who have contributed to the success of
  478. this library.
  479. Conversion Routines
  480. -------------------
  481.  
  482.  
  483. The stdlib conversion routines follow a uniform format of storing the data
  484. to be converted and returned.  Most routines accept input and return data
  485. of either an ASCII string of characters, stored in the ES:DI register, or
  486. integers, stored in the DX:AX register.  If a value is just a 16 or 8-bit
  487. value then it will be stored in AX or AL.
  488.  
  489. Since there is a possibility of an error in the input values to be converted,
  490. such as it does not contain a proper value to convert, we use the
  491. carry flag to show error status.  If the error flag is set then an error has
  492. occured and things are okay if the carry flag is clear.
  493.  
  494.  
  495.  
  496.  
  497.  
  498. Routine:  ATOL (2)
  499. ------------------
  500.  
  501.  
  502. Category:             Conversion Routine
  503.  
  504. Registers on Entry:   ES:DI- Points at string to convert
  505.  
  506. Registers on Return:  DX:AX- Long integer converted from string
  507.               ES:DI- Points at first non-digit (ATOL2 only)
  508.  
  509. Flags Affected:       Carry flag- Error status
  510.  
  511. Examples of Usage:
  512.               gets         ;Get a string from user
  513.               ATOL         ;Convert to a value in DX:AX
  514.  
  515.  
  516. Description:  ATOL converts the string of digits that ES:DI points at to a
  517.           long (signed) integer value and returns this value in DX:AX.
  518.           Note that the routine stops on the first non-digit.
  519.           If the string does not begin with a digit, this routine returns
  520.           zero.  The only exception to the "string of digits" only rule is
  521.           that the number can have a preceding minus sign to denote a
  522.           negative number.  Note that this routine does not allow leading
  523.           spaces.  ATOL2 works in a similar fashion except it doesn't
  524.           preserve the DI register.  That is, ATOL2 leaves DI pointing at
  525.           the first character beyond the string of digits.  ATOL/ATOL2 both
  526.           return the carry flag clear if it  translated the string of
  527.           digits without error.  It returns the carry flag set if overflow
  528.           occurred.
  529.  
  530.  
  531. Include:                  stdlib.a or conv.a
  532.  
  533.  
  534.  
  535. Routine:  AtoUL (2)
  536. -------------------
  537.  
  538. Category:            Conversion Routine
  539.  
  540. Register on entry:   ES:DI- address of the string to be converted
  541.  
  542. Register on return:  DX:AX- 32-bit unsigned integer
  543.              ES:DI- Points at first character beyond digits (ATOUL2
  544.                 only)
  545.  
  546. Flags affected:      Carry flag- Set if error, clear if okay.
  547.  
  548. Examples of Usage:
  549.              les InputString
  550.              AtoUL
  551.  
  552.  
  553. Description:  AtoUL converts the string pointed by ES:DI to a 32-bit unsigned
  554.           integer.  It places the 32-bit unsigned integer into the memory
  555.           address pointed by DX:AX. If there is an error in conversion,
  556.           the carry flag will set to one. If there is not an error, the
  557.           carry flag will be set to zero.
  558.  
  559.           ATOUL2 does not preserve DI.  It returns with DI pointing at
  560.           the first non-digit character in the string.
  561.  
  562. Include:        stdlib.a or conv.a
  563.  
  564.  
  565.  
  566. Routine:    ATOU (2)
  567. --------------------
  568.  
  569. Category:            Conversion Routine
  570.  
  571. Register on entry:   ES:DI points at string to convert
  572.  
  573. Register on return:  AX-    unsigned 16-bit integer
  574.              ES:DI- points at first non-digit (ATOU2 only)
  575.  
  576. Flags affected:      carry flag - error status
  577.  
  578. Example of Usage:
  579.  
  580. Description:    ATOU converts an ASCII string of digits, pointed to by ES:DI,
  581.         to unsigned integer format. It places the unsigned 16-bit
  582.         integer, converted from the string, into the AX register.
  583.         ATOI works the same, except it handle unsigned 16-bit integers
  584.         in the range 0..65535.
  585.  
  586.         ATOU2 leaves DI pointing at the first non-digit in the string.
  587.  
  588. Include:        stdlib.a or conv.a
  589.  
  590.  
  591.  
  592. Routine: ATOH (2)
  593. -----------------
  594.  
  595. Category:             Conversion Routine
  596.  
  597. Registers on Entry:   ES:DI- Points to string to convert
  598.  
  599. Registers on Return:  AX- Unsigned 16-bit integer converted from hex string
  600.               DI (ATOH2)- First character beyond string of hex digits
  601.  
  602. Flags Affected:       Carry = Error status
  603.  
  604. Example of Usage:
  605.               les  DI, Str2Convrt
  606.               atoh                  ;Convert to value in AX.
  607.               putw                  ;Print word in AX.
  608.  
  609.  
  610. Description:  ATOH converts a string of hexadecimal digits, pointed to by
  611.           ES:DI, into unsigned 16-bit numeric form. It returns the value in
  612.           the AX register.  If there is an error in conversion, the carry
  613.           flag will set to one.  If there is not an error, the carry flag
  614.           will be clear.  ATOH2 works the same except it leaves DI
  615.           pointing at the first character beyond the string of hex digits.
  616.  
  617. Include:        stdlib.a or conv.a
  618.  
  619.  
  620. Routine: ATOLH (2)
  621. ------------------
  622.  
  623. Category:             Conversion Routine
  624.  
  625. Registers on Entry:   ES:DI- Points to string to convert
  626.  
  627. Registers on Return:  DX:AX- Unsigned 32-bit integer converted from hex string
  628.               DI (ATOLH2)- First character beyond string of hex digits
  629.  
  630. Flags Affected:       Carry = Error status
  631.  
  632. Example of Usage:
  633.               les  DI, Str2Convrt
  634.               atolh                 ;Convert to value in DX:AX
  635.  
  636. Description:  ATOLH converts a string of hexadecimal digits, pointed to by
  637.           ES:DI, into unsigned 32-bit numeric form. It returns the value in
  638.           the DX:AX register.  If there is an error in conversion, the carry
  639.           flag will set to one.  If there is not an error, the carry flag
  640.           will be clear.  ATOLH2 works the same except it leaves the DI
  641.           register pointing at the first non-hex digit.
  642.  
  643.  
  644. Include:        stdlib.a or conv.a
  645.  
  646.  
  647.  
  648. Routine:   ATOI (2)
  649. -------------------
  650.  
  651. Category:             Conversion Routine
  652.  
  653. Register on entry:    ES:DI- Points at string to convert.
  654.  
  655. Register on return:   AX- Integer converted from string.
  656.               DI (ATOI2)- First character beyond string of digits.
  657.  
  658. Flags affected:       Error status
  659.  
  660. Examples of Usage:
  661.               les  DI, Str2Convrt
  662.               atoi                 ;Convert to value in AX
  663.  
  664.  
  665. Description:   Works just like ATOL except it translates the string to a
  666.            signed 16-bit integer rather than a 32-bit long integer.
  667.  
  668.  
  669. Include:              stdlib.a or conv.a
  670.  
  671.  
  672. Routine ITOA (2,M)
  673. ------------------
  674.  
  675. Category:             Conversion Routine
  676.  
  677. Registers on Entry:   AX- Signed 16-bit value to convert to a string
  678.               ES:DI- Pointer to buffer to hold result (ITOA/ITOA2
  679.                  only).
  680.  
  681. Registers on Return:  ES:DI- Pointer to string containing converted
  682.               characters (ITOA/ITOAM only).
  683.               ES:DI- Pointer to zero-terminating byte of converted
  684.                  string (ITOA2 only).
  685.  
  686. Flags Affected:       Carry flag is set on memory allocation error (ITOAM only)
  687.  
  688. Examples of Usage:
  689.               mov     ax, -1234
  690.               ITOAM                   ;Convert to string.
  691.               puts                    ;Print it.
  692.               free                    ;Deallocate string.
  693.  
  694.               mov     di, seg buffer
  695.               mov     es, di
  696.               lea     di, buffer
  697.               mov     ax, -1234
  698.               ITOA              ;Leaves string in BUFFER.
  699.  
  700.               mov     di, seg buffer
  701.               mov     es, di
  702.               lea     di, buffer
  703.               mov     ax, -1234
  704.               ITOA2              ;Leaves string in BUFFER and
  705.                           ;ES:DI pointing at end of string.
  706.  
  707.  
  708. Description:    These routines convert an integer value to a string of
  709.         characters which represent that integer.  AX contains the
  710.         signed integer you wish to convert.
  711.  
  712.         ITOAM automatically allocates storage on the heap for the
  713.         resulting string, you do not have to pre-allocate this
  714.         storage.  ITOAM returns a pointer to the (zero-terminated)
  715.         string in the ES:DI registers.  It ignores the values in
  716.         ES:DI on input.
  717.  
  718.         ITOA requires that the caller allocate the storage for the
  719.         string (maximum you will need is seven bytes) and pass a
  720.         pointer to this buffer in ES:DI.  ITOA returns with ES:DI
  721.         pointing at the beginning of the converted string.
  722.  
  723.         ITOA2 also requires that you pass in the address of a buffer
  724.         in the ES:DI register pair.  However, it returns with ES:DI
  725.         pointing at the zero-terminating byte of the string.  This
  726.         lets you easily build up longer strings via multiple calls
  727.         to routines like ITOA2.
  728.  
  729. Include:        stdlib.a or conv.a
  730.  
  731.  
  732.  
  733. Routine:   UTOA (2,M)
  734. ---------------------
  735.  
  736. Category:            Conversion Routine
  737.  
  738. Registers on entry:   AX - unsigned 16-bit integer to convert to a string
  739.               ES:DI- Pointer to buffer to hold result (UTOA/UTOA2
  740.                  only).
  741.  
  742. Registers on Return:  ES:DI- Pointer to string containing converted
  743.               characters (UTOA/UTOAM only).
  744.               ES:DI- Pointer to zero-terminating byte of converted
  745.                  string (UTOA2 only).
  746.  
  747. Flags affected:       Carry set denotes malloc error (UTOAM only)
  748.  
  749. Example of Usage:
  750.               mov     ax, 65000
  751.               utoa
  752.               puts
  753.               free
  754.  
  755.               mov     di, seg buffer
  756.               mov     es, di
  757.               lea     di, buffer
  758.               mov     ax, -1234
  759.               ITOA              ;Leaves string in BUFFER.
  760.  
  761.               mov     di, seg buffer
  762.               mov     es, di
  763.               lea     di, buffer
  764.               mov     ax, -1234
  765.               ITOA2              ;Leaves string in BUFFER and
  766.                           ;ES:DI pointing at end of string.
  767.  
  768.  
  769. Description:    UTOAx converts a 16-bit unsigned integer value in AX to a
  770.         string of characters which represents that value.  UTOA,
  771.         UTOA2, and UTOAM behave in a manner analogous to ITOAx.  See
  772.         the description of those routines for more details.
  773.  
  774.  
  775. Include:       stdlib.a or conv.a
  776.  
  777.  
  778.  
  779. Routine:   HTOA (2,M)
  780. ---------------------
  781.  
  782. Category:            Conversion Routine
  783.  
  784. Registers on entry:   AL - 8-bit integer to convert to a string
  785.               ES:DI- Pointer to buffer to hold result (HTOA/HTOA2
  786.                  only).
  787.  
  788. Registers on Return:  ES:DI- Pointer to string containing converted
  789.               characters (HTOA/HTOAM only).
  790.               ES:DI- Pointer to zero-terminating byte of converted
  791.                  string (HTOA2 only).
  792.  
  793. Flags affected:      Carry set denotes memory allocation error (HTOAM only)
  794.  
  795.  
  796. Description:    The HTOAx routines convert an 8-bit value in AL to the two-
  797.         character hexadecimal representation of that byte.  Other
  798.         that that, they behave just like ITOAx/UTOAx.  Note that
  799.         the resulting buffer must have at least three bytes for
  800.         HTOA/HTOA2.
  801.  
  802.  
  803. Include:        stdlib.a or conv.a
  804.  
  805.  
  806. Routine:  WTOA (2,M)
  807. --------------------
  808.  
  809. Category:             Conversion Routine
  810.  
  811. Registers on Entry:   AX- 16-bit value to convert to a string
  812.               ES:DI- Pointer to buffer to hold result (WTOA/WTOA2
  813.                  only).
  814.  
  815. Registers on Return:  ES:DI- Pointer to string containing converted
  816.               characters (WTOA/WTOAM only).
  817.               ES:DI- Pointer to zero-terminating byte of converted
  818.                  string (WTOA2 only).
  819.  
  820. Flags Affected:       Carry set denotes memory allocation error (WTOAM only)
  821.  
  822. Example of Usage:
  823.               Like WTOA above
  824.  
  825.  
  826. Description:  WTOAx converts the 16-bit value in AX to a string of four
  827.           hexadecimal digits. It behaves exactly like HTOAx except
  828.           it outputs four characters (and requires a five byte buffer).
  829.  
  830.  
  831. Include:        stdlib.a or conv.a
  832.  
  833.  
  834.  
  835. Routine:  LTOA (2,M)
  836. --------------------
  837.  
  838. Category:             Conversion Routine
  839.  
  840. Registers on entry:   DX:AX (contains a signed 32 bit integer)
  841.               ES:DI- Pointer to buffer to hold result (LTOA/LTOA2
  842.                  only).
  843.  
  844. Registers on Return:  ES:DI- Pointer to string containing converted
  845.               characters (LTOA/LTOAM only).
  846.               ES:DI- Pointer to zero-terminating byte of converted
  847.                  string (LTOA2 only).
  848.  
  849. Flags affected:       Carry set if memory allocation error (LTOAM only)
  850.  
  851.  
  852. Example of Usage: 
  853.             mov    di, seg buffer    ;Get address of storage
  854.             mov    es, di        ; buffer.
  855.             lea    di, buffer
  856.             mov    ax, word ptr value
  857.             mov    dx, word ptr value+2
  858.             ltoa
  859.  
  860. Description:    LtoA converts the 32-bit signed integer in DX:AX to a string
  861.         of characters.  LTOA stores the string at the address specified
  862.         in ES:DI (there must be at least twelve bytes available at
  863.         this address) and returns with ES:DI pointing at this buffer.
  864.         LTOA2 works the same way, except it returns with ES:DI
  865.         pointing at the zero terminating byte.  LTOAM allocates
  866.         storage for the string on the heap and returns a pointer
  867.         to the string in ES:DI.
  868.  
  869. Include:        stdlib.a or conv.a
  870.  
  871.  
  872.  
  873. Routine:  ULTOA (2,M)
  874. ---------------------
  875.  
  876. Category:             Conversion Routine
  877.  
  878. Registers on Entry:   DX:AX- Unsigned 32-bit value to convert to a string
  879.               ES:DI- Pointer to buffer to hold result (LTOA/LTOA2
  880.                  only).
  881. Registers on Return:  ES:DI- Pointer to string containing converted
  882.               characters (LTOA/LTOAM only).
  883.               ES:DI- Pointer to zero-terminating byte of converted
  884.                  string (LTOA2 only).
  885.  
  886. Flags Affected:       Carry is set if malloc error (ULTOAM only)
  887.  
  888. Example of Usage:  
  889.                       Like LTOA
  890.  
  891.  
  892. Description:  Like LTOA except this routine handles unsigned integer values.
  893.  
  894. Include:    stdlib.a or conv.a
  895.  
  896.  
  897.  
  898. Routine:  SPrintf (2,M)
  899. -----------------------
  900.  
  901. Category:            Conversion Routine
  902.              In-Memory Formatting Routine
  903.  
  904. Registers on entry:  CS:RET - Pointer to format string and operands of the
  905.                   sprintf routine
  906.              ES:DI-   Address of buffer to hold output string
  907.                   (sprintf/sprintf2 only)
  908.  
  909. Register on return:  ES:DI register - pointer to a string containing
  910.                       output data (sprintf/sprintfm only).
  911.                       Pointer to zero-terminating byte at the
  912.                       end of the converted string (sprintf2
  913.                       only).
  914.  
  915. Flags affected:      Carry is set if memory allocation error (sprintfm only).
  916.  
  917. Example of Usage:
  918.              sprintfm
  919.              db      "I=%i, U=%u, S=%s",13,10,0
  920.              db      i,u,s
  921.              puts
  922.              free
  923.  
  924.  
  925. Description:   SPrintf is an in-memory formatting routine. It is similar to
  926.            C's sprintf routine.
  927.  
  928.            The programmer selects the maximum length of the output string.
  929.            SPrintf works in a manner quite similar to printf, except sprintf
  930.            writes its output to a string variable rather than to the stdlib
  931.            standard output.
  932.  
  933.            SPrintfm, by default, allocates 2048 characters for the string
  934.            and then deallocates any unnecessary storage.  An external
  935.            variable, sp_MaxBuf, holds the number of bytes to allocate upon
  936.            entry into sprintfm.  If you wish to allocate more or less than
  937.            2048 bytes when calling sprintf, simply change the value of this
  938.            public variable (type is word).  Sprintfm calls malloc to
  939.            allocate the storage dynamically.  You should call free to
  940.            return this buffer to the heap when you are through with it.
  941.  
  942.            Sprintf and Sprintf2 expect you to pass the address of a buffer
  943.            to them.  You are responsible for supplying a sufficiently
  944.            sized buffer to hold the result.
  945.  
  946. Include:             stdlib.a or conv.a
  947.  
  948.  
  949.  
  950. Routine:  SScanf
  951. ----------------
  952.  
  953. Category:              Conversion Routine
  954.                Formatted In-Memory Conversion Routine
  955.  
  956. Registers on Entry:    ES:DI - points at string containing values to convert
  957.  
  958. Registers on return:   None
  959.  
  960. Flags affected:           None
  961.  
  962. Example of Usage:
  963.  
  964.           ; this code reads the values for i, j, and s from the characters
  965.           ; starting at memory location Buffer.
  966.  
  967.                les   di, Buffer
  968.                SScanf
  969.                db    "%i %i %s",0
  970.                dd     i, j, s
  971.  
  972.  
  973. Description:  SScanf provides formatted input in a fashion analogous to scanf.
  974.               The difference is that scanf reads in a line of text from the
  975.               stdlib standard input whereas you pass the address of a sequence
  976.               of characters to SScanf in es:di.
  977.  
  978.  
  979. Include:                stdlib.a or conv.a
  980.  
  981.  
  982.  
  983.  
  984. Routine:  ToLower
  985. -----------------
  986.  
  987. Category:            Conversion Routine
  988.  
  989. Register on entry:   AL- Character to (possibly) convert
  990.                 to lower case.
  991.  
  992. Register on return:  AL- Converted character.
  993.  
  994. Flags affected:      None
  995.  
  996. Example of usage:
  997.              mov     al, char
  998.              ToLower
  999.  
  1000.  
  1001. Description:  ToLower checks the character in the AL register, if it is upper
  1002.           case it converts it to lower case.  If it is anything else,
  1003.           ToLower leaves the value in AL unchanged.  For high performance
  1004.           this routine is implemented as a macro rather than as a
  1005.           procedure call.  This routine is so short you would spend more
  1006.           time actually calling the routine than executing the code inside.
  1007.           However, the code is definitely longer than a (far) procedure
  1008.           call, so if space is critical and you're invoking this code
  1009.           several times, you may want to convert it to a procedure call to
  1010.           save a little space.
  1011.  
  1012.  
  1013. Include:             stdlib.a or conv.a
  1014.  
  1015.  
  1016.  
  1017. Routine:   ToUpper
  1018. ------------------
  1019.  
  1020. Category:             Conversion Routine
  1021.  
  1022. Registers on Entry:   AL- Character to (possibly) convert to upper case
  1023.  
  1024. Registers on Return:  AL- Converted character
  1025.  
  1026. Flags Affected:       None
  1027.  
  1028. Example of Usage:
  1029.               mov  al, char
  1030.               ToUpper
  1031.  
  1032.  
  1033. Description:  ToUpper checks the character in the AL register, if it is lower
  1034.           case it converts it to upper case.  If it is anything else,
  1035.           ToUpper leaves the value in AL unchanged.  For high performance
  1036.           this routine is implemented as a macro rather than as a
  1037.           procedure call (see ToLower, above).
  1038.  
  1039.  
  1040. Include:              stdlib.a or conv.a
  1041.  
  1042.  
  1043. =====================
  1044. Date & Time  Routines
  1045. =====================
  1046.  
  1047. These routines convert DOS system times and dates to/from ASCII strings.
  1048. They appear in this section rather than conversions because we eventually
  1049. intend to add date and time arithmetic to the package.
  1050.  
  1051. Note the time to string conversion routines do not output the hundredths of
  1052. a second.  Most applications do not need (or want) this.  If you want
  1053. hundredths of a second you can easily write a routine (using this code) or
  1054. modify the existing code to suit your purposes.
  1055.  
  1056.  
  1057.  
  1058.  
  1059. Routine:  DTOA (2,m)
  1060. --------------------
  1061.  
  1062. Category:       Date/Time Routines
  1063.  
  1064. Author:        Randall Hyde
  1065.  
  1066. Registers on Entry:
  1067.             CX-    Current year (in the range 1980-2099)
  1068.             DL-    Current day
  1069.             DH-    Current month
  1070.             ES:DI-    Points at buffer with room for at least
  1071.                 nine bytes (DTOA/DTOA2 only).
  1072.  
  1073.  
  1074. Registers on Return:     ES:DI-    DTOA sticks a string of the form MM/DD/YY
  1075.                 into a buffer allocated on the heap (DTOAM
  1076.                 only).
  1077.  
  1078.             ES:DI-    Points at the zero terminating byte at the
  1079.                 end of the string (DTOA2 only).
  1080.  
  1081. Flags Affected:       carry-    Set if memory allocation error (DTOAM only).
  1082.  
  1083.  
  1084. Example of Usage:
  1085.  
  1086.             mov    ah, 2ah        ;Call DOS to get the system
  1087.             int    21h        ; time (also see xDTOA)
  1088.             lesi    TodaysDate    ;Buffer to store string.
  1089.             DTOA            ;Convert date to string.
  1090.  
  1091.             mov    ah, 2ah
  1092.             int    21h
  1093.             lesi    TodaysDate2
  1094.             DTOA2
  1095.  
  1096.             mov    ah, 2ah
  1097.             int    21h
  1098.             DTOAM            ;ES:DI is allocated on heap.
  1099.  
  1100. Description:
  1101.  
  1102. DTOA converts a DOS system date (in CX/DX) to an ASCII string and deposits
  1103. the characters into a buffer specified by ES:DI on input.  ES:DI must be at
  1104. least nine bytes long (eight bytes for mm/dd/yy plus the zero terminating
  1105. byte).
  1106.  
  1107. DTOA2 converts a DOS system date to an ASCII string just like DTOA above.
  1108. The only difference is that it does not preserve DI.  It leaves DI pointing
  1109. at the zero terminating byte at the end of the string.  This routine is use-
  1110. ful for building up long strings with a date somewhere in the middle.
  1111.  
  1112. DTOAM works like DTOA except you do not pass the pointer to a buffer in ES:DI.
  1113. Instead, DTOAM allocates nine bytes for the string on the heap.  It returns
  1114. a pointer to this new string in ES:DI.
  1115.  
  1116. Include:              stdlib.a or date.a
  1117.  
  1118. Routine:  xDTOA (2,m)
  1119. ---------------------
  1120.  
  1121. Category:       Date/Time Routines
  1122.  
  1123. Author:        Randall Hyde
  1124.  
  1125. Registers on Entry:
  1126.             ES:DI-    Points at buffer with room for at least
  1127.                 nine bytes (xDTOA/xDTOA2 only).
  1128.  
  1129.  
  1130. Registers on Return:     ES:DI-    DTOA sticks a string of the form MM/DD/YY
  1131.                 into a buffer allocated on the heap (xDTOAM
  1132.                 only).
  1133.  
  1134.             ES:DI-    Points at the zero terminating byte at the
  1135.                 end of the string (xDTOA2 only).
  1136.  
  1137. Flags Affected:       carry-    Set if memory allocation error (xDTOAM only).
  1138.  
  1139.  
  1140. Example of Usage:
  1141.  
  1142.             lesi    TodaysDate    ;Buffer to store string.
  1143.             xDTOA            ;Convert date to string.
  1144.  
  1145.             lesi    TodaysDate2
  1146.             xDTOA2
  1147.  
  1148.             mov    ah, 2ah
  1149.             int    21h
  1150.             xDTOAM            ;ES:DI is allocated on heap.
  1151.  
  1152. Description:
  1153.  
  1154. These routines work just like DTOA, DTOA2, and DTOAM except you do not pass
  1155. in the date to them, they call DOS to read the current system date and
  1156. convert that to a string.
  1157.  
  1158. Include:              stdlib.a or date.a
  1159.  
  1160.  
  1161. Routine:  LDTOA (2,m)
  1162. ---------------------
  1163.  
  1164. Category:       Date/Time Routines
  1165.  
  1166. Author:        Randall Hyde
  1167.  
  1168. Registers on Entry:
  1169.             CX-    Current year (in the range 1980-2099)
  1170.             DL-    Current day
  1171.             DH-    Current month
  1172.             ES:DI-    Points at buffer with room for at least
  1173.                 nine bytes (DTOA/DTOA2 only).
  1174.  
  1175.  
  1176. Registers on Return:     ES:DI-    DTOA sticks a string of the form "mmm dd, yyyy"
  1177.                 into a buffer allocated on the heap (LDTOAM
  1178.                 only).
  1179.  
  1180.             ES:DI-    Points at the zero terminating byte at the
  1181.                 end of the string (LDTOA2 only).
  1182.  
  1183. Flags Affected:       carry-    Set if memory allocation error (LDTOAM only).
  1184.  
  1185.  
  1186. Example of Usage:
  1187.  
  1188.             mov    ah, 2ah        ;Call DOS to get the system
  1189.             int    21h        ; time (also see xDTOA)
  1190.             lesi    TodaysDate    ;Buffer to store string.
  1191.             LDATE            ;Convert date to string.
  1192.  
  1193.             mov    ah, 2ah
  1194.             int    21h
  1195.             lesi    TodaysDate2
  1196.             LDTOA2
  1197.  
  1198.             mov    ah, 2ah
  1199.             int    21h
  1200.             LDTOAM            ;ES:DI is allocated on heap.
  1201.  
  1202. Description:
  1203.  
  1204. These routines work just like the DTOA, DTOA2, and DTOAM routines except they
  1205. output their date in the form "mmm dd, yyyy", e.g., Jan 1, 1980.
  1206.  
  1207. Include:              stdlib.a or date.a
  1208.  
  1209. Routine:  xLDTOA (2,m)
  1210. ---------------------
  1211.  
  1212. Category:       Date/Time Routines
  1213.  
  1214. Author:        Randall Hyde
  1215.  
  1216. Registers on Entry:
  1217.             ES:DI-    Points at buffer with room for at least
  1218.                 nine bytes (xLDTOA/xLDTOA2 only).
  1219.  
  1220.  
  1221. Registers on Return:     ES:DI-    Sticks a string of the form MMM DD, YYYY
  1222.                 into a buffer allocated on the heap (xLDTOAM
  1223.                 only).
  1224.  
  1225.             ES:DI-    Points at the zero terminating byte at the
  1226.                 end of the string (xLDTOA2 only).
  1227.  
  1228. Flags Affected:       carry-    Set if memory allocation error (xLDTOAM only).
  1229.  
  1230.  
  1231. Example of Usage:
  1232.  
  1233.             lesi    TodaysDate    ;Buffer to store string.
  1234.             xLDTOA            ;Convert date to string.
  1235.  
  1236.             lesi    TodaysDate2
  1237.             xLDTOA2
  1238.  
  1239.             mov    ah, 2ah
  1240.             int    21h
  1241.             xLDTOAM            ;ES:DI is allocated on heap.
  1242.  
  1243. Description:
  1244.  
  1245. Similar to xDTOA, xDTOA2, and xDTOAM except these routines produce strings of
  1246. the form "MMM DD, YYYY".
  1247.  
  1248. Include:              stdlib.a or date.a
  1249.  
  1250. Routine:  ATOD (2)
  1251. ------------------
  1252.  
  1253. Category:       Date/Time Routines
  1254.  
  1255. Author:        Randall Hyde
  1256.  
  1257. Registers on Entry:
  1258.             ES:DI-    Points at string containing date to convert.
  1259.  
  1260.  
  1261. Registers on Return:     CX-    Year (1980-2099)
  1262.             DH-    Month (1-12)
  1263.             DL-    Day (1-31)
  1264.             ES:DI-    Points at first non-date string (ATOD2 only)
  1265.  
  1266. Flags Affected:           carry-    Set if bad date format.
  1267.  
  1268.  
  1269. Example of Usage:
  1270.  
  1271.             lesi    TodaysDate    ;Buffer containing string.
  1272.             ATOD            ;Convert string to date.
  1273.             jc    Error
  1274.  
  1275.             lesi    TodaysDate    ;Buffer containing string.
  1276.             ATOD2            ;Convert string to date.
  1277.             jc    Error
  1278.  
  1279. Description:
  1280.  
  1281. ATOD converts an ASCII string of the form "mm/dd/yy" or "mm-dd-yy" to a DOS
  1282. format date.  It returns the carry flag set if there is a parse error (that
  1283. is, the string is not in one of these two forms) or if the month, date, or
  1284. year values are out of range (including specifying Feb 29th on non-leap years).
  1285.  
  1286. ATOD2 works just like ATOD except it does not preserve DI.  It leaves DI
  1287. pointing at the first non-date character encountered in the string.
  1288.  
  1289. Include:              stdlib.a or date.a
  1290.  
  1291. Routine:  ATOT (2)
  1292. ------------------
  1293.  
  1294. Category:       Date/Time Routines
  1295.  
  1296. Author:        Randall Hyde
  1297.  
  1298. Registers on Entry:
  1299.             ES:DI-    Points at string containing time to convert.
  1300.  
  1301.  
  1302. Registers on Return:     CH-    Hour (0..23)
  1303.             CL-    Minutes (0..59)
  1304.             DH-    Seconds (0..59)
  1305.             DL-    Seconds/100 (0..99)
  1306.  
  1307.             ES:DI-    Points at first character which is not a part
  1308.                 of the parsed time (ATOT2 only).
  1309.  
  1310. Flags Affected:           carry-    Set if bad time format.
  1311.  
  1312.  
  1313. Example of Usage:
  1314.  
  1315.             lesi    CurrentTime    ;Buffer containing string.
  1316.             ATOT            ;Convert string to time.
  1317.             jc    Error
  1318.  
  1319.             lesi    CurrentTime    ;Buffer containing string.
  1320.             ATOT2            ;Convert string to time.
  1321.             jc    Error
  1322.  
  1323.  
  1324. Description:
  1325.  
  1326. ATOT converts an ASCII string of the form "hh:mm:ss" or "hh:mm:ss.xxx" to a DOS
  1327. format date.  It returns the carry flag set if there is a parse error (that
  1328. is, the string is not in one of these two forms) or if the hours, minutes,
  1329. seconds, or hundredth values are out of range.  If the string does not contain
  1330. 1/100ths of a second, this routine returns zero in DL.
  1331.  
  1332. ATOT2 works just like ATOT except it does not preserve DI.  It leaves DI
  1333. pointing at the first character beyond the time characters.
  1334.  
  1335. Include:              stdlib.a or time.a
  1336.  
  1337. Routine:  TTOA (2,m)
  1338. --------------------
  1339.  
  1340. Category:       Date/Time Routines
  1341.  
  1342. Author:        Randall Hyde
  1343.  
  1344. Registers on Entry:
  1345.             CH-    Hour (0..23)
  1346.             CL-    Minutes (0..59)
  1347.             DH-    Seconds (0..59)
  1348.             DL-    1/100 seconds (0..99)
  1349.             ES:DI-    Points at buffer with room for at least
  1350.                 nine bytes (TTOA/TTOA2 only).
  1351.  
  1352.  
  1353. Registers on Return:     ES:DI-    Sticks a string of the form hh:mm:ss
  1354.                 into a buffer allocated on the heap (TTOAM
  1355.                 only).
  1356.  
  1357.             ES:DI-    Points at the zero terminating byte at the
  1358.                 end of the string (TTOA2 only).
  1359.  
  1360. Flags Affected:       carry-    Set if memory allocation error (TTOAM only).
  1361.  
  1362.  
  1363. Example of Usage:
  1364.  
  1365.             mov    ah, 2ch        ;Call DOS to get the system
  1366.             int    21h        ; time (also see xTTOA)
  1367.             lesi    CurrentTime    ;Buffer to store string.
  1368.             TTOA            ;Convert Time to string.
  1369.  
  1370.             mov    ah, 2ch
  1371.             int    21h
  1372.             lesi    CurTime2
  1373.             TTOA2
  1374.  
  1375.             mov    ah, 2ch
  1376.             int    21h
  1377.             TTOAM            ;ES:DI is allocated on heap.
  1378.  
  1379. Description:
  1380.  
  1381. TTOA converts the DOS system time in CX/DX to a string and stores the string
  1382. at the location specified by ES:DI.  ES:DI must point at a buffer with at
  1383. least nine characters in it (for a string of the form hh:mm:ss followed by
  1384. a zero terminating byte).
  1385.  
  1386. TTOA2 works like TTOA except it does not preserve DI.  It leaves DI pointing
  1387. at the zero terminating byte in the string.  This is useful for generating
  1388. long strings in memory of which TTOA is one component.
  1389.  
  1390. TTOAM is like TTOA except it automatically allocates storage for the string
  1391. on the heap.
  1392.  
  1393. Include:              stdlib.a or time.a
  1394.  
  1395. Routine:  xTTOA (2,m)
  1396. ---------------------
  1397.  
  1398. Category:       Date/Time Routines
  1399.  
  1400. Author:        Randall Hyde
  1401.  
  1402. Registers on Entry:
  1403.             ES:DI-    Points at buffer with room for at least
  1404.                 nine bytes (xTTOA/xTTOA2 only).
  1405.  
  1406.  
  1407. Registers on Return:     ES:DI-    Sticks a string of the form HH:MM:SS
  1408.                 into a buffer allocated on the heap xTTOAM
  1409.                 only).
  1410.  
  1411.             ES:DI-    Points at the zero terminating byte at the
  1412.                 end of the string (xTTOA2 only).
  1413.  
  1414. Flags Affected:       carry-    Set if memory allocation error (xTTOAM only).
  1415.  
  1416.  
  1417. Example of Usage:
  1418.  
  1419.             lesi    CurrentTime    ;Buffer to store string.
  1420.             xTTOA            ;Convert time to string.
  1421.  
  1422.             lesi    CurTime2
  1423.             xTTOA2
  1424.  
  1425.             xTTOAM            ;ES:DI is allocated on heap.
  1426.  
  1427. Description:
  1428.  
  1429. These routines work just like TTOA, TTOA2, and TTOAM except you do not pass
  1430. in the time to them, they call DOS to read the current system time and
  1431. convert that to a string.
  1432.  
  1433. Include:              stdlib.a or time.a
  1434.  
  1435. File I/O Routines
  1436. -----------------
  1437.  
  1438. Although MS-DOS provides some fairly decent file I/O facilities, the MS-DOS
  1439. file routines are all block oriented.  That is, there is no simple routine
  1440. you can call to read a single character from a file (the most common case).
  1441. Although you can create a buffer consisting of a single byte and call MS-DOS
  1442. to read a single character into that buffer, this is very slow.  The standard
  1443. library file I/O routines provide a set of buffered I/O routines for sequent-
  1444. ially accessed files.  These routines are suitable only for files which you
  1445. sequentially read or sequentially write.  They do not work with random access
  1446. files nor can you alternately read and write to the file.  However, most file
  1447. accesses fall into the category of sequential read or write so the Standard
  1448. Library routines will work fine in most cases.  In other cases, MS-DOS
  1449. provides a reasonable API so there really isn't a need for augmentation in
  1450. the Standard Library.
  1451.  
  1452. The Standard Library provides routines to OPEN a file (for reading or writing
  1453. only), CREATE a new file and open it for writing, CLOSE a file, FLUSH the file
  1454. buffers associated with a file, GET a character from a file, READ a block of
  1455. bytes from a file, PUT a single character to a file, or write a block of chars
  1456. to a file.
  1457.  
  1458. Note that you can use the standard I/O redirection operations to redirect the
  1459. standard input and output to routines which read and write bytes through a
  1460. file.  Consider the following short routine:
  1461.  
  1462. Redir2File    proc    far
  1463.         push    ds
  1464.         push    es
  1465.         push    di
  1466.         mov    di, seg MyFileVar
  1467.         mov    ds, di
  1468.  
  1469.         les    di, ds:MyFileVar
  1470.         fputc
  1471.  
  1472.         pop    di
  1473.         pop    es
  1474.         pop    ds
  1475.         ret
  1476. Redir2File    endp
  1477.  
  1478. This routine, when called, writes the character in AL to the file specified
  1479. by the file variable "MyFileVar" (see an explanation of the FPUTC routine
  1480. for more details).  You can selectively redirect all of the standard output
  1481. routines through this procedure (hence sending all standard output to the
  1482. file) using the Standard Library SetOutAdrs routine:
  1483.  
  1484.         lesi    Redir2File
  1485.         SetOutAdrs
  1486.  
  1487.         <use print, printf, puts, puti, etc. here, all output
  1488.          goes to the file rather than to the screen.>
  1489.  
  1490.         lesi    PutcStdOut    ;Default DOS output
  1491.         SetOutAdrs
  1492.  
  1493.         <Now all output goes back to the DOS standard output>
  1494.  
  1495. You can also preserve the previous output address using the code:
  1496.  
  1497.         lesi    Redir2File
  1498.         PushOutAdrs
  1499.  
  1500.         <use print, printf, puts, puti, etc. here, all output
  1501.          goes to the file rather than to the screen.>
  1502.  
  1503.         PopOutAdrs
  1504.  
  1505.         <Now all output goes back to the previous handler.>
  1506.  
  1507.  
  1508. You can do the same thing with the standard input routines when redirecting
  1509. input from a file, though this is less useful.
  1510.  
  1511.  
  1512. All file I/O routines in the library use a "File Variable" to keep track of
  1513. the specified file.  *THIS IS NOT THE SAME THING AS A DOS FILE HANDLE!*
  1514. "FileVar" is a structure defined in the "file.a" include file.  For each file
  1515. you open/close, you must create a unique file variable.
  1516.  
  1517.  
  1518. Routine:  FOPEN
  1519. ---------------
  1520.  
  1521. Category:             File I/O
  1522.  
  1523. Registers on Entry:    AX contains file open mode
  1524.                 (0=open for read, 1=open for write)
  1525.             ES:DI points at a file variable.
  1526.             DX:SI points at a file name.
  1527.  
  1528. Registers on return:    Carry is set/clear for error/no error.
  1529.             AX contains (DOS) error code if carry is set.
  1530.  
  1531. Flags affected:
  1532.             Carry denotes error.
  1533.  
  1534. Example of Usage:
  1535.  
  1536. MyFileVar        FileVar    <>
  1537. MyFileName        db    "file.nam"
  1538.             .
  1539.             .
  1540.             .
  1541.             mov    ax, 0            ;Open for reading
  1542.             lesi    MyFileVar        ;Ptr to file variable.
  1543.             ldxi    MyFileName        ;Ptr to file name.
  1544.             fopen
  1545.             jc    Error
  1546.  
  1547. Description:
  1548.  
  1549. fopen opens a sequential file for reading or writing.  It calls DOS to 
  1550. actually open the file and then sets up appropriate internal variables (in
  1551. the FileVar variable) to provide efficient blocked I/O.
  1552.  
  1553. Include:              stdlib.a or file.a
  1554.  
  1555. Routine:  FCREATE
  1556. -----------------
  1557.  
  1558. Category:             File I/O
  1559.  
  1560. Registers on Entry:    
  1561.             ES:DI points at a file variable.
  1562.             DX:SI points at a file name.
  1563.  
  1564. Registers on return:    Carry is set/clear for error/no error.
  1565.             AX contains (DOS) error code if carry is set.
  1566.  
  1567. Flags affected:
  1568.             Carry denotes error.
  1569.  
  1570. Example of Usage:
  1571.  
  1572. MyFileVar        FileVar    <>
  1573. MyFileName        db    "file.nam"
  1574.             .
  1575.             .
  1576.             .
  1577.             lesi    MyFileVar        ;Ptr to file variable.
  1578.             ldxi    MyFileName        ;Ptr to file name.
  1579.             fcreate
  1580.             jc    Error
  1581.  
  1582. Description:
  1583.  
  1584. fcreate opens a new file for reading.  If the file already exists, fcreate
  1585. will delete it and create a new one.  Other than this, the behavior is
  1586. quite similar to fopen.
  1587.  
  1588. Include:              stdlib.a or file.a
  1589.  
  1590. Routine:  FCLOSE
  1591. ----------------
  1592.  
  1593. Category:             File I/O
  1594.  
  1595. Registers on Entry:    
  1596.             ES:DI points at a file variable.
  1597.  
  1598. Registers on return:    Carry is set/clear for error/no error.
  1599.             AX contains (DOS) error code if carry is set.
  1600.  
  1601. Flags affected:
  1602.             Carry denotes error.
  1603.  
  1604. Example of Usage:
  1605.  
  1606. MyFileVar        FileVar    <>
  1607.             .
  1608.             .
  1609.             .
  1610.             lesi    MyFileVar        ;Ptr to file variable.
  1611.             fclose
  1612.             jc    Error
  1613.  
  1614. Description:
  1615.  
  1616. fclose closes a file opened by fcreate or fopen.  Note that you *must* use
  1617. this call to close the file (rather than using DOS' close call).  There may
  1618. be "hot" data present in internal buffers.  This call flushes such data to
  1619. the file.
  1620.  
  1621. Note that you must make this call before quitting your application.  DOS will
  1622. automatically close all files upon quitting, but DOS will not automatically
  1623. flush any hot data to disk upon program termination.
  1624.  
  1625. Include:              stdlib.a or file.a
  1626.  
  1627. Routine:  FFLUSH
  1628. ----------------
  1629.  
  1630. Category:             File I/O
  1631.  
  1632. Registers on Entry:    
  1633.             ES:DI points at a file variable.
  1634.  
  1635. Registers on return:    Carry is set/clear for error/no error.
  1636.             AX contains (DOS) error code if carry is set.
  1637.  
  1638. Flags affected:
  1639.             Carry denotes error.
  1640.  
  1641. Example of Usage:
  1642.  
  1643. Ptr2FileVar        dd    MyFileVar
  1644.             .
  1645.             .
  1646.             .
  1647.             les    di, Ptr2FileVar        ;Ptr to file variable.
  1648.             fflush
  1649.             jc    Error
  1650.  
  1651. Description:
  1652.  
  1653. fflush will write any "hot" data (data written to the file by an application
  1654. which is currently sitting in internal buffers) to the file.  It is a good
  1655. idea to occassionally flush files to disk if you do not write the data to
  1656. the file all at once.  This helps prevents loss of data in the event of an
  1657. abnormal termination.
  1658.  
  1659. Include:              stdlib.a or file.a
  1660.  
  1661. Routine:  FGETC
  1662. ---------------
  1663.  
  1664. Category:             File I/O
  1665.  
  1666. Registers on Entry:    
  1667.             ES:DI points at a file variable.
  1668.  
  1669. Registers on return:    AL contains byte read (if no error, C=0).
  1670.             AX contains (DOS) error code if carry is set.
  1671.  
  1672. Flags affected:
  1673.             Carry denotes error.
  1674.  
  1675. Example of Usage:
  1676.  
  1677. Ptr2FileVar        dd    MyFileVar
  1678.             .
  1679.             .
  1680.             .
  1681.             les    di, Ptr2FileVar        ;Ptr to file variable.
  1682.             fgetc
  1683.             jc    Error
  1684.             <AL contains byte read at this point>
  1685.  
  1686. Description:
  1687.  
  1688. fgetc reads a single byte from a file opened for reading.  On EOF the carry
  1689. flag will be set and AX will contain zero.
  1690.  
  1691. Include:              stdlib.a or file.a
  1692.  
  1693. Routine:  FREAD
  1694. ---------------
  1695.  
  1696. Category:             File I/O
  1697.  
  1698. Registers on Entry:    
  1699.             ES:DI points at a file variable.
  1700.             DX:SI points at the destination block.
  1701.             CX contains the number of bytes to read.
  1702.  
  1703. Registers on return:    AX contains actual # of bytes read (if no error, C=0).
  1704.             AX contains (DOS) error code if carry is set (AX=0
  1705.                 denotes EOF).
  1706.  
  1707. Flags affected:
  1708.             Carry denotes error.
  1709.  
  1710. Example of Usage:
  1711.  
  1712. MyFileVar        FileVar    <>
  1713. MyBlock            db    256 dup (?)
  1714.             .
  1715.             .
  1716.             .
  1717.             lesi    MyFileVar        ;Ptr to file variable.
  1718.             ldxi    MyBlock            ;Place to put data.
  1719.             mov    cx, 256            ;# of bytes to read.
  1720.             fread
  1721.             jc    Error
  1722.  
  1723. Description:
  1724.  
  1725. fread lets you read a block of bytes from a file opened for reading.  This
  1726. call is generally *much* faster than reading a string of single bytes if you
  1727. want to read a large number of bytes at one time.
  1728.  
  1729. Include:              stdlib.a or file.a
  1730.  
  1731. Routine:  FPUTC
  1732. ---------------
  1733.  
  1734. Category:             File I/O
  1735.  
  1736. Registers on Entry:    
  1737.             ES:DI points at a file variable.
  1738.             AL    contains the character to write to the file.
  1739.  
  1740. Registers on return:
  1741.             AX contains (DOS) error code if carry is set.
  1742.  
  1743. Flags affected:
  1744.             Carry denotes error.
  1745.  
  1746. Example of Usage:
  1747.  
  1748. Ptr2FileVar        dd    MyFileVar
  1749.             .
  1750.             .
  1751.             .
  1752.             les    di, Ptr2FileVar        ;Ptr to file variable.
  1753.             mov    al, Char2Write
  1754.             fputc
  1755.             jc    Error
  1756.  
  1757. Description:
  1758.  
  1759. fputs writes a single byte to a file opened for writing (or opened via the
  1760. fcreate call).  It writes the byte in AL to the output file.  Note that data
  1761. written via this call may not be written directly to the file.  For performance
  1762. reasons the fputc routine buffers up the data in memory and writes large blocks
  1763. of data to the file.  If you need to ensure that the data is properly written
  1764. to the file you will need to make a call to fclose or fflush.
  1765.  
  1766. Include:              stdlib.a or file.a
  1767.  
  1768. Routine:  FWRITE
  1769. ----------------
  1770.  
  1771. Category:             File I/O
  1772.  
  1773. Registers on Entry:    
  1774.             ES:DI points at a file variable.
  1775.             DX:SI points at the source block.
  1776.             CX contains the number of bytes to write.
  1777.  
  1778. Registers on return:    AX contains actual # of bytes written (if no error).
  1779.             AX contains (DOS) error code if carry is set (AX=0
  1780.                 denotes EOF).
  1781.  
  1782. Flags affected:
  1783.             Carry denotes error.
  1784.  
  1785. Example of Usage:
  1786.  
  1787. MyFileVar        FileVar    <>
  1788. MyBlock            db    256 dup (?)
  1789.             .
  1790.             .
  1791.             .
  1792.             lesi    MyFileVar        ;Ptr to file variable.
  1793.             ldxi    MyBlock            ;Place to put data.
  1794.             mov    cx, 256            ;# of bytes to read.
  1795.             fwrite
  1796.             jc    Error
  1797.  
  1798. Description:
  1799.  
  1800. fwrite lets you write a block of bytes to a file opened for writing.  This
  1801. call is generally *much* faster than writing a string of single bytes if you
  1802. want to read a large number of bytes at one time.  Note that fwrite, like
  1803. fputc, buffers up data before writing it to disk.  If you need to commit
  1804. data to the disk surface at some point, you must call the fflush or fclose
  1805. routines.
  1806.  
  1807. Include:              stdlib.a or file.a
  1808.  
  1809. Floating Point Routines
  1810. -----------------------
  1811.  
  1812. The floating point routines provide a basic floating point package for
  1813. 80x86 assembly language users.  The floating point package deals with
  1814. four different floating point formats: IEEE 32-bit, 64-bit, and 80-bit
  1815. formats, and an internal 81-bit format.  The external formats mostly
  1816. support the IEEE standard except for certain esoteric values such as
  1817. denormalized numbers, NaNs, infinities, and other such cases.
  1818.  
  1819. The package provides two "pseudo-registers", a floating point accumulator
  1820. and a floating point operand.  It provides routines to load and store these
  1821. pseudo-registers from memory operands (using the various formats) and then
  1822. all other operations apply to these two operands.  All computations use the
  1823. internal 81-bit floating point format.  The package automatically converts
  1824. between the internal format and the external format when loading and storing
  1825. values.
  1826.  
  1827. Do not write code which assumes the internal format is 81 bits.  This format
  1828. will change in the near future when I get a chance to add guard bits to
  1829. all the computations.  If your code assumes 81 bits, it will break at that
  1830. point.  Besides, there is no reason your code should count on the size of
  1831. the internal operations anyway.  Stick with the IEEE formats and you'll
  1832. be much better off (since your code can be easily upgraded to deal with
  1833. numeric coprocessors).
  1834.  
  1835. WARNING: These routines have not been sufficiently tested as of 10/10/91.
  1836. Use them with care.  Report any problems with these routines to Randy Hyde
  1837. via the electronic addresses provided in this document or by sending a
  1838. written report to UC Riverside.  As I get more time, I will further test
  1839. these routines and add additional functions to the package.
  1840.  
  1841.                     *** Randy Hyde
  1842.  
  1843.  
  1844.  
  1845. Routine:  lsfpa
  1846. ---------------
  1847.  
  1848. Category:             Floating point Routine
  1849.  
  1850. Registers on entry:   ES:DI points at a single precision (32-bit) value to load
  1851.  
  1852. Registers on return:  None
  1853.  
  1854. Flags affected:       None
  1855.  
  1856. Example of Usage:
  1857.             les di, FPValue
  1858.             lsfpa
  1859.  
  1860. Description:    LSFPA loads a single precision floating point value into the
  1861.         internal floating point accumulator.  It also converts the
  1862.         32-bit format to the internal 81-bit format used by the
  1863.         floating point package.
  1864.  
  1865. Include:    stdlib.a or fp.a
  1866.  
  1867. Routine:  ssfpa
  1868. ---------------
  1869.  
  1870. Category:             Floating point Routine
  1871.  
  1872. Registers on entry:   ES:DI points at a single precision (32-bit) value where
  1873.               this routine should store the floating point acc.
  1874.  
  1875. Registers on return:  None
  1876.  
  1877. Flags affected:       Carry set if conversion error.
  1878.  
  1879. Example of Usage:
  1880.             les di, FPValue
  1881.             ssfpa
  1882.  
  1883. Description:    SSFPA stores the floating point accumulator into a single
  1884.         precision variable in memory (pointed at by ES:DI).  It
  1885.         converts the value from the 81-bit format to the 32-bit
  1886.         value before storing the result.   The 64-bit mantissa used
  1887.         by the FP package is rounded to 24 bits during the store.
  1888.         The exponent could be out of range.  If this occurs, SSFPA
  1889.         returns with the carry flag set.
  1890.  
  1891. Include:    stdlib.a or fp.a
  1892.  
  1893.  
  1894. Routine:  ldfpa
  1895. ---------------
  1896.  
  1897. Category:             Floating point Routine
  1898.  
  1899. Registers on entry:   ES:DI points at a double precision (64-bit) value to load
  1900.  
  1901. Registers on return:  None
  1902.  
  1903. Flags affected:       None
  1904.  
  1905. Example of Usage:
  1906.             les di, FPValue
  1907.             ldfpa
  1908.  
  1909. Description:    LDFPA loads a double precision floating point value into the
  1910.         internal floating point accumulator.  It also converts the
  1911.         64-bit format to the internal 81-bit format used by the
  1912.         floating point package.
  1913.  
  1914. Include:    stdlib.a or fp.a
  1915.  
  1916. Routine:  sdfpa
  1917. ---------------
  1918.  
  1919. Category:             Floating point Routine
  1920.  
  1921. Registers on entry:   ES:DI points at a double precision (64-bit) value where
  1922.               this routine should store the floating point acc.
  1923.  
  1924. Registers on return:  None
  1925.  
  1926. Flags affected:       Carry set if conversion error.
  1927.  
  1928. Example of Usage:
  1929.             les di, FPValue
  1930.             sdfpa
  1931.  
  1932. Description:    SDFPA stores the floating point accumulator into a double
  1933.         precision variable in memory (pointed at by ES:DI).  It
  1934.         converts the value from the 81-bit format to the 64-bit
  1935.         value before storing the result.   The 64-bit mantissa used
  1936.         by the FP package is rounded to 51 bits during the store.
  1937.         The exponent could be out of range.  If this occurs, SDFPA
  1938.         returns with the carry flag set.
  1939.  
  1940. Include:    stdlib.a or fp.a
  1941.  
  1942.  
  1943. Routine:  lefpa
  1944. ---------------
  1945.  
  1946. Category:             Floating point Routine
  1947.  
  1948. Registers on entry:   ES:DI points at an extended precision (80-bit) value to
  1949.               load
  1950.  
  1951. Registers on return:  None
  1952.  
  1953. Flags affected:       None
  1954.  
  1955. Example of Usage:
  1956.             les di, FPValue
  1957.             lefpa
  1958.  
  1959. Description:    LEFPA loads an extended precision floating point value into
  1960.         the internal floating point accumulator.  It also converts the
  1961.         80-bit format to the internal 81-bit format used by the
  1962.         floating point package.
  1963.  
  1964. Include:    stdlib.a or fp.a
  1965.  
  1966.  
  1967. Routine:  lefpal
  1968. ----------------
  1969.  
  1970. Category:             Floating point Routine
  1971.  
  1972. Registers on entry:   CS:RET points at an extended precision (80-bit) value to
  1973.               load
  1974.  
  1975. Registers on return:  None
  1976.  
  1977. Flags affected:       None
  1978.  
  1979. Example of Usage:
  1980.             lefpal
  1981.             dt    1.345e-3
  1982.  
  1983. Description:    LEFPAL loads an extended precision floating point value into
  1984.         the internal floating point accumulator.  It also converts the
  1985.         80-bit format to the internal 81-bit format used by the
  1986.         floating point package.
  1987.  
  1988.         Unlike LEFPA, LEFPAL gets its operand directly from the code
  1989.         stream.  You must follow the call to lefpal with a ten-byte
  1990.         (80-bit) floating point constant.
  1991. Include:    stdlib.a or fp.a
  1992.  
  1993. Routine:  sefpa
  1994. ---------------
  1995.  
  1996. Category:             Floating point Routine
  1997.  
  1998. Registers on entry:   ES:DI points at an extended precision (80-bit) value
  1999.               where this routine should store the floating point acc.
  2000.  
  2001. Registers on return:  None
  2002.  
  2003. Flags affected:       Carry set if conversion error.
  2004.  
  2005. Example of Usage:
  2006.             les di, FPValue
  2007.             sefpa
  2008.  
  2009. Description:    SEFPA stores the floating point accumulator into an extended
  2010.         precision variable in memory (pointed at by ES:DI).  It
  2011.         converts the value from the 81-bit format to the 80-bit
  2012.         value before storing the result.
  2013.  
  2014.         The exponent could be out of range.  If this occurs, SEFPA
  2015.         returns with the carry flag set.
  2016.  
  2017. Include:    stdlib.a or fp.a
  2018.  
  2019.  
  2020. Routine:  lsfpo
  2021. ---------------
  2022.  
  2023. Category:             Floating point Routine
  2024.  
  2025. Registers on entry:   ES:DI points at a single precision (32-bit) value to load
  2026.  
  2027. Registers on return:  None
  2028.  
  2029. Flags affected:       None
  2030.  
  2031. Example of Usage:
  2032.             les di, FPValue
  2033.             lsfpo
  2034.  
  2035. Description:    LSFPA loads a single precision floating point value into the
  2036.         internal floating point operand.  It also converts the
  2037.         32-bit format to the internal 81-bit format used by the
  2038.         floating point package.
  2039.  
  2040. Include:    stdlib.a or fp.a
  2041.  
  2042.  
  2043. Routine:  ldfpo
  2044. ---------------
  2045.  
  2046. Category:             Floating point Routine
  2047.  
  2048. Registers on entry:   ES:DI points at a double precision (64-bit) value to load
  2049.  
  2050. Registers on return:  None
  2051.  
  2052. Flags affected:       None
  2053.  
  2054. Example of Usage:
  2055.             les di, FPValue
  2056.             ldfpo
  2057.  
  2058. Description:    LDFPO loads a double precision floating point value into the
  2059.         internal floating point operand.  It also converts the
  2060.         64-bit format to the internal 81-bit format used by the
  2061.         floating point package.
  2062.  
  2063. Include:    stdlib.a or fp.a
  2064.  
  2065.  
  2066. Routine:  lefpo
  2067. ---------------
  2068.  
  2069. Category:             Floating point Routine
  2070.  
  2071. Registers on entry:   ES:DI points at an extended precision (80-bit) value to
  2072.               load
  2073.  
  2074. Registers on return:  None
  2075.  
  2076. Flags affected:       None
  2077.  
  2078. Example of Usage:
  2079.             les di, FPValue
  2080.             lefpo
  2081.  
  2082. Description:    LEFPO loads an extended precision floating point value into
  2083.         the internal floating point operand.  It also converts the
  2084.         80-bit format to the internal 81-bit format used by the
  2085.         floating point package.
  2086.  
  2087. Include:    stdlib.a or fp.a
  2088.  
  2089.  
  2090. Routine:  lefpol
  2091. ----------------
  2092.  
  2093. Category:             Floating point Routine
  2094.  
  2095. Registers on entry:   CS:RET points at an extended precision (80-bit) value to
  2096.               load
  2097.  
  2098. Registers on return:  None
  2099.  
  2100. Flags affected:       None
  2101.  
  2102. Example of Usage:
  2103.             lefpal
  2104.             dt    1.345e-3
  2105.  
  2106. Description:    LEFPOL loads an extended precision floating point value into
  2107.         the internal floating point operand.  It also converts the
  2108.         80-bit format to the internal 81-bit format used by the
  2109.         floating point package.
  2110.  
  2111.         Unlike LEFPO, LEFPOL gets its operand directly from the code
  2112.         stream.  You must follow the call to lefpal with a ten-byte
  2113.         (80-bit) floating point constant.
  2114. Include:    stdlib.a or fp.a
  2115.  
  2116.  
  2117. Routine:  itof
  2118. --------------
  2119.  
  2120. Category:             Floating point Routine
  2121.  
  2122. Registers on entry:   AX contains a signed integer value
  2123.  
  2124. Registers on return:  None
  2125.  
  2126. Flags affected:       None
  2127.  
  2128. Example of Usage:
  2129.             mov    ax, -1234
  2130.             itof
  2131.  
  2132. Description:    ITOF converts the 16-bit signed integer in AX to a floating
  2133.         point value, storing the result in the floating point
  2134.         accumuator.
  2135.  
  2136. Include:    stdlib.a or fp.a
  2137.  
  2138.  
  2139. Routine:  utof
  2140. --------------
  2141.  
  2142. Category:             Floating point Routine
  2143.  
  2144. Registers on entry:   AX contains an unsigned integer value
  2145.  
  2146. Registers on return:  None
  2147.  
  2148. Flags affected:       None
  2149.  
  2150. Example of Usage:
  2151.             mov    ax, -1234
  2152.             itof
  2153.  
  2154. Description:    UTOF converts the 16-bit unsigned integer in AX to a floating
  2155.         point value, storing the result in the floating point
  2156.         accumuator.
  2157.  
  2158. Include:    stdlib.a or fp.a
  2159.  
  2160.  
  2161. Routine:  ultof
  2162. ---------------
  2163.  
  2164. Category:             Floating point Routine
  2165.  
  2166. Registers on entry:   DX:AX contains an unsigned 32-bit integer value
  2167.  
  2168. Registers on return:  None
  2169.  
  2170. Flags affected:       None
  2171.  
  2172. Example of Usage:
  2173.             mov    dx, word ptr val32+2
  2174.             mov    ax, word ptr val32
  2175.             ultof
  2176.  
  2177. Description:    ULTOF converts the 32-bit unsigned integer in DX:AX to a
  2178.         floating point value, storing the result in the floating
  2179.         point accumuator.
  2180.  
  2181. Include:    stdlib.a or fp.a
  2182.  
  2183.  
  2184. Routine:  ltof
  2185. --------------
  2186.  
  2187. Category:             Floating point Routine
  2188.  
  2189. Registers on entry:   DX:AX contains a signed 32-bit integer value
  2190.  
  2191. Registers on return:  None
  2192.  
  2193. Flags affected:       None
  2194.  
  2195. Example of Usage:
  2196.             mov    dx, word ptr val32+2
  2197.             mov    ax, word ptr val32
  2198.             ltof
  2199.  
  2200. Description:    LTOF converts the 32-bit signed integer in DX:AX to a
  2201.         floating point value, storing the result in the floating
  2202.         point accumuator.
  2203.  
  2204. Include:    stdlib.a or fp.a
  2205.  
  2206.  
  2207. Routine:  ftoi
  2208. --------------
  2209.  
  2210. Category:             Floating point Routine
  2211.  
  2212. Registers on entry:   None
  2213.  
  2214. Registers on return:  AX contains 16-bit signed integer
  2215.  
  2216. Flags affected:       Carry is set if conversion error occurs.
  2217.  
  2218. Example of Usage:
  2219.             ftoi
  2220.             puti        ;Print AX as integer value
  2221.  
  2222.  
  2223. Description:    FTOI converts the floating point accumulator value to a
  2224.         16-bit signed integer and returns the result in AX.  If
  2225.         the floating point number will not fit in AX, FTOI returns
  2226.         with the carry flag set.
  2227.  
  2228. Include:    stdlib.a or fp.a
  2229.  
  2230.  
  2231. Routine:  ftou
  2232. --------------
  2233.  
  2234. Category:             Floating point Routine
  2235.  
  2236. Registers on entry:   None
  2237.  
  2238. Registers on return:  AX contains 16-bit unsigned integer
  2239.  
  2240. Flags affected:       Carry is set if conversion error occurs.
  2241.  
  2242. Example of Usage:
  2243.             ftou
  2244.             putu        ;Print AX as an unsigned value
  2245.  
  2246.  
  2247. Description:    FTOU converts the floating point accumulator value to a
  2248.         16-bit unsigned integer and returns the result in AX.  If
  2249.         the floating point number will not fit in AX, FTOU returns
  2250.         with the carry flag set.
  2251.  
  2252. Include:    stdlib.a or fp.a
  2253.  
  2254.  
  2255. Routine:  ftol
  2256. --------------
  2257.  
  2258. Category:             Floating point Routine
  2259.  
  2260. Registers on entry:   None
  2261.  
  2262. Registers on return:  DX:AX contains a 32-bit signed integer
  2263.  
  2264. Flags affected:       Carry is set if conversion error occurs.
  2265.  
  2266. Example of Usage:
  2267.             ftol
  2268.             putl        ;Print DX:AX as integer value
  2269.  
  2270.  
  2271. Description:    FTOL converts the floating point accumulator value to a
  2272.         32-bit signed integer and returns the result in DX:AX.  If
  2273.         the floating point number will not fit in DX:AX, FTOL returns
  2274.         with the carry flag set.
  2275.  
  2276. Include:    stdlib.a or fp.a
  2277.  
  2278.  
  2279. Routine:  ftoul
  2280. ---------------
  2281.  
  2282. Category:             Floating point Routine
  2283.  
  2284. Registers on entry:   None
  2285.  
  2286. Registers on return:  DX:AX contains a 32-bit unsigned integer
  2287.  
  2288. Flags affected:       Carry is set if conversion error occurs.
  2289.  
  2290. Example of Usage:
  2291.             ftoul
  2292.             putul        ;Print DX:AX as an integer value
  2293.  
  2294.  
  2295. Description:    FTOUL converts the floating point accumulator value to a
  2296.         32-bit unsigned integer and returns the result in DX:AX.  If
  2297.         the floating point number will not fit in DX:AX, FTOUL returns
  2298.         with the carry flag set.
  2299.  
  2300. Include:    stdlib.a or fp.a
  2301.  
  2302.  
  2303. Routine:  fpadd
  2304. ---------------
  2305.  
  2306. Category:             Floating point Routine
  2307.  
  2308. Registers on entry:   None
  2309.  
  2310. Registers on return:  None
  2311.  
  2312. Flags affected:       None
  2313.  
  2314. Example of Usage:
  2315.             fpadd
  2316.  
  2317. Description:    FPADD adds the floating point operand to the floating point
  2318.         accumulator leaving the result in the floating point
  2319.         accumulator.
  2320.  
  2321. Include:    stdlib.a or fp.a
  2322.  
  2323.  
  2324. Routine:  fpsub
  2325. ---------------
  2326.  
  2327. Category:             Floating point Routine
  2328.  
  2329. Registers on entry:   None
  2330.  
  2331. Registers on return:  None
  2332.  
  2333. Flags affected:       None
  2334.  
  2335. Example of Usage:
  2336.             fpsub
  2337.  
  2338. Description:    FPSUB subtracts the floating point operand from the floating
  2339.         point accumulator leaving the result in the floating point
  2340.         accumulator.
  2341.  
  2342. Include:    stdlib.a or fp.a
  2343.  
  2344.  
  2345. Routine:  fpcmp
  2346. ---------------
  2347.  
  2348. Category:             Floating point Routine
  2349.  
  2350. Registers on entry:   None
  2351.  
  2352. Registers on return:  AX contains result of comparison.
  2353.  
  2354. Flags affected:       As appropriate for a comparison.  You can use the
  2355.               conditional branches to check the comparison after
  2356.               calling this routine.  Be sure to use the *signed*
  2357.               conditional jumps (e.g., JG, JGE, etc.).
  2358.  
  2359. Example of Usage:
  2360.             fpcmp
  2361.             jge    FPACCgeFPOP
  2362.  
  2363. Description:    FPCMP compares the floating point accumulator to the
  2364.         floating point operand and sets the flags according to the
  2365.         result of the comparison.  It also returns a value in AX
  2366.         as follows:
  2367.  
  2368.             AX    Result
  2369.             -1    FPACC < FPOP
  2370.              0    FPACC = FPOP
  2371.              1    FPACC > FPOP
  2372.  
  2373. Include:    stdlib.a or fp.a
  2374.  
  2375.  
  2376. Routine:  fpmul
  2377. --------------
  2378.  
  2379. Category:             Floating point Routine
  2380.  
  2381. Registers on entry:   None
  2382.  
  2383. Registers on return:  None
  2384.  
  2385. Flags affected:       None
  2386.  
  2387. Example of Usage:
  2388.             fpmul
  2389.  
  2390. Description:    FPMUL multiplies the floating point accumulator by the floating
  2391.         point operand and leaves the result in the floating point
  2392.         accumulator.
  2393.  
  2394. Include:    stdlib.a or fp.a
  2395.  
  2396.  
  2397. Routine:  fpdiv
  2398. ---------------
  2399.  
  2400. Category:             Floating point Routine
  2401.  
  2402. Registers on entry:   None
  2403.  
  2404. Registers on return:  None
  2405.  
  2406. Flags affected:       None
  2407.  
  2408. Example of Usage:
  2409.             fpdiv
  2410.  
  2411. Description:    FPDIV divides the floating point accumulator by the floating
  2412.         point operand and leaves the result in the floating point
  2413.         accumulator.
  2414.  
  2415. Include:    stdlib.a or fp.a
  2416.  
  2417.  
  2418. Routine:  ftoa (2,m)
  2419. --------------------
  2420.  
  2421. Category:             Floating point Routine
  2422.  
  2423. Registers on entry:   ES:DI points at buffer to hold result (ftoa/ftoa2 only)
  2424.               AL- Field width for floating point value.
  2425.               AH- Number of positions to the right of the dec pt.
  2426.  
  2427. Registers on return:  ES:DI points at beginning of string (ftoa/ftoam only)
  2428.               ES:DI points at zero terminating byte (ftoa2 only)
  2429.  
  2430. Flags affected:       Carry is set if malloc error (ftoam only)
  2431.  
  2432. Example of Usage:
  2433.             mov    di, seg buffer
  2434.             mov    es, di
  2435.             lea    di, buffer
  2436.             mov    ah, 2        ;Two digits after "."
  2437.             mov    al, 10        ;Use a total of ten positions
  2438.             ftoa
  2439.  
  2440.  
  2441.  
  2442. Description:    FTOA (2,M) converts the value in the floating point accumulator
  2443.         to a string of characters which represent that value.  These
  2444.         routines use a decimal representation.  The value in AH is
  2445.         the number of digits to put after the decimal point, AL
  2446.         contains the total field width (including room for the sign
  2447.         and decimal point).  The field width specification works
  2448.         just like Pascal or FORTRAN.  If the number will not fit in
  2449.         the specified field width, FTOA outputs a bunch of "#"
  2450.         characters.
  2451.  
  2452.         FTOA stores the converted string at the address specified by
  2453.         ES:DI upon entry.  There must be at least AL+1 bytes at this
  2454.         address.  It returns with ES:DI pointing at the start of this
  2455.         buffer.
  2456.  
  2457.         FTOA2 works just like FTOA except it does not preserve DI.
  2458.         It returns with DI pointing at the zero terminating byte.
  2459.  
  2460.         FTOAM allocates storage for the string on the heap and returns
  2461.         a pointer to the converted string in ES:DI.
  2462.  
  2463.         Note: this routine preserves the value in the floating point
  2464.         accumulator but it wipes out the value in the floating point
  2465.         operand.
  2466.  
  2467. Include:    stdlib.a or fp.a
  2468.  
  2469.  
  2470. Routine:  etoa (2,m)
  2471. --------------------
  2472.  
  2473. Category:             Floating point Routine
  2474.  
  2475. Registers on entry:   ES:DI points at buffer to hold result (etoa/etoa2 only)
  2476.               AL- Field width for floating point value.
  2477.  
  2478. Registers on return:  ES:DI points at beginning of string (etoa/etoam only)
  2479.               ES:DI points at zero terminating byte (etoa2 only)
  2480.  
  2481. Flags affected:       Carry is set if malloc error (etoam only)
  2482.  
  2483. Example of Usage:
  2484.             mov    al, 14        ;Use a total of 14 positions
  2485.             etoam
  2486.             puts
  2487.             putcr
  2488.             free
  2489.  
  2490.  
  2491.  
  2492. Description:    ETOA (2,M) converts the value in the floating point accumulator
  2493.         to a string of characters which represent that value.  These
  2494.         routines use an exponential (scientific notation)
  2495.         representation.  AL contains the field width.  It contains
  2496.         the number of print position to use when outputting the
  2497.         number.  The field width specification works just like Pascal
  2498.         or FORTRAN.  If the number will not fit in the specified
  2499.         field width, ETOA outputs a bunch of "#" characters.
  2500.  
  2501.         ETOA stores the converted string at the address specified by
  2502.         ES:DI upon entry.  There must be at least AL+1 bytes at this
  2503.         address.  It returns with ES:DI pointing at the start of this
  2504.         buffer.
  2505.  
  2506.         ETOA2 works just like ETOA except it does not preserve DI.
  2507.         It returns with DI pointing at the zero terminating byte.
  2508.  
  2509.         ETOAM allocates storage for the string on the heap and returns
  2510.         a pointer to the converted string in ES:DI.
  2511.  
  2512.         Note: this routine preserves the value in the floating point
  2513.         accumulator but it wipes out the value in the floating point
  2514.         operand.
  2515.  
  2516. Include:    stdlib.a or fp.a
  2517.  
  2518.  
  2519. Routine:  atof
  2520. --------------
  2521.  
  2522. Category:             Floating point Routine
  2523.  
  2524. Registers on entry:   ES:DI points at a string containing the representation
  2525.               of a floating point number in ASCII form.
  2526.  
  2527. Registers on return:  None
  2528.  
  2529. Flags affected:       None
  2530.  
  2531. Example of Usage:
  2532.             les    di, FPStr
  2533.             atof
  2534.  
  2535.  
  2536. Description:    ATOF converts the string pointed at by ES:DI into a floating
  2537.         point value and leaves this value in the floating point
  2538.         accumulator.  Legal floating point values are described
  2539.         by the following regular expression:
  2540.  
  2541.  
  2542.         {" "}* {+ | -} ( ([0-9]+ {"." [0-9]*}) | ("." [0-9]+)}
  2543.                 {(e | E) {+ | -} [0-9] {[0-9]*}}
  2544.  
  2545.  "{}" denote optional items.
  2546.  "|"  denotes OR.
  2547.  "()" groups items together.
  2548.  
  2549.  
  2550.  
  2551. Include:    stdlib.a or fp.a
  2552.  
  2553. Memory Management Routines
  2554. --------------------------
  2555.  
  2556. The stdlib memory management routines let you dynamically allocate storage on
  2557. the heap.  These routines are somewhat similar to those provided by the "C"
  2558. programming language.  However, these routines do not perform garbage
  2559. collection, as this would introduce too many restrictions and have a very
  2560. adverse effect on speed.
  2561.  
  2562. The following paragraph gives a description of how the memory management
  2563. routines work.  These routines may be updated in future revisions, however,
  2564. so you should never make assumptions about the structure of the memory
  2565. management record (described below) or else your code may not work on the
  2566. next revision.
  2567.  
  2568. The allocation/deallocation routines should be fairly fast.  Malloc and free
  2569. use a modified first/next fit algorithm which lets the system quickly find a
  2570. memory block of the desired size without undue fragmentation problems (average
  2571. case).  The memory manager data structure has an overhead of eight bytes
  2572. (meaning each malloc operation requires at least eight more bytes than you ask
  2573. for) and a granularity of 16 bytes.  The overhead (eight bytes) per allocated
  2574. block may seem rather high, but that is part of the price to pay for faster
  2575. malloc and free routines.  All pointers are far pointers and each new item is
  2576. allocated on a paragraph boundary.  The current memory manager routines always
  2577. allocate (n+8) bytes, rounding up to the next multiple of 16 if the result is
  2578. not evenly divisible by sixteen.  The first eight bytes of the structure are
  2579. used by the memory management routines, the remaining bytes are available for
  2580. use by the caller (malloc, et. al., return a pointer to the first byte beyond
  2581. the memory management overhead structure).
  2582.  
  2583. NOTE: There was a major change in the way this package works starting with
  2584. version 30 of the library.  Prior to version 30, MemInit required a parameter
  2585. in the DX register to determine where to allocate the heap and how much
  2586. storage to allocate.  Furthermore, the older versions called DOS to deallocate
  2587. memory then reallocate it for the heap.  Finally, the older versions required
  2588. that you set up a global variable "PSP" containing the program segment
  2589. prefix value.
  2590.  
  2591. As of version 30, MemInit was split into two routines: MemInit and MemInit2.
  2592. MemInit allocates all of available memory (like the standard version of the
  2593. earlier MemInit) whereas MemInit2 lets you specify the location and size
  2594. of the heap.  The new version calls DOS to get the PSP (so you don't need
  2595. to declare the PSP variable just for MemInit).  The new version does not
  2596. reallocate memory blocks with DOS calls (which created some problems,
  2597. especially with debugger programs).  Finally the new versions work fine
  2598. with ".EXE" files which do not get all leftover memory allocated to them.
  2599.  
  2600. Most older STDLIB programs will work just fine with the new MemInit routine.
  2601. If you relied on MemInit to reallocate memory for you, or if you specified
  2602. the location of the heap, you will need to modify your program to use these
  2603. new versions of the MemInit routine.
  2604.  
  2605.  
  2606. Routine:  MemInit
  2607. -----------------
  2608.  
  2609. Category:               Memory Management Routine
  2610.  
  2611. Registers on Entry:     Nothing
  2612. Globals Affected:       zzzzzzseg - segment name of the last segment in your
  2613.                     program
  2614.  
  2615. Registers on return:    CX - number of paragraphs actually reserved by MemInit
  2616.  
  2617.  
  2618. Flags affected:         None
  2619.  
  2620. Example of Usage:
  2621.                         ; Don't forget to set up
  2622.                         ; zzzzzzseg before calling
  2623.                         ; MemInit
  2624.             MemInit
  2625.  
  2626.  
  2627. Description:  This routine initializes the memory manager system.  You must
  2628.           call it before using any routines which call any of the memory
  2629.           manager procedures (since a good number of the stdlib routines
  2630.           call the memory manager, you should get in the habit of always
  2631.           calling this routine.)  The system will "die a horrible death"
  2632.           if you call a memory manager routine (like malloc) without first
  2633.           calling MemInit.
  2634.  
  2635.           This routine expects you to define (and set up) a global
  2636.           names: zzzzzzseg.  "zzzzzzseg" is a dummy segment which
  2637.           must be the name of the very last segment defined in your
  2638.           program.  MemInit uses the name of this segment to determine the
  2639.           address of the last byte in your program.  If you do not
  2640.           declare this segment last, the memory manager will overwrite
  2641.           anything which follows zzzzzzseg.  The "shell.asm" file
  2642.           provides you with a template for your programs which properly
  2643.           defines this segment.
  2644.  
  2645.           On return from MemInit, the CX register contains the number of
  2646.           paragraphs actually allocated.
  2647.  
  2648.  
  2649. Include:                stdlib.a or memory.a
  2650.  
  2651. Routine:  MemInit2
  2652. ------------------
  2653.  
  2654. Category:               Memory Management Routine
  2655.  
  2656. Registers on Entry:     ES-    segment address of the start of the heap.
  2657.             CX-    Number of paragraphs to allocate for the heap.
  2658.  
  2659. Registers on return:    None
  2660. Flags affected:         None
  2661.  
  2662. Example of Usage:
  2663.             mov    cx, seg HeapSeg
  2664.             mov    es, cx
  2665.             mov    cx, HeapSize        ;In paragraphs!
  2666.             MemInit2
  2667.  
  2668.  
  2669. Description:  This routine initializes the memory manager system.  You must
  2670.           call it before using any routines which call any of the memory
  2671.           manager procedures (since a good number of the stdlib routines
  2672.           call the memory manager, you should get in the habit of always
  2673.           calling this routine.)  The system will "die a horrible death"
  2674.           if you call a memory manager routine (like malloc) without first
  2675.           calling MemInit2 (or MemInit).
  2676.  
  2677.           This routine lets you decide where the heap lies in memory
  2678.           (as opposed to MemInit which uses all available bytes from
  2679.           the end of your program to the end of memory).
  2680.  
  2681.           Note: you should only call MemInit or MemInit2 once in your
  2682.           program.
  2683.  
  2684. Include:                stdlib.a or memory.a
  2685.  
  2686. Routine:  Malloc
  2687. ----------------
  2688.  
  2689. Category:              Memory Management Routine
  2690.  
  2691. Registers on Entry:    CX - number of bytes to reserve
  2692.  
  2693. Registers on return:   CX - number of bytes actually reserved by Malloc
  2694.                ES:DI - ptr to 1st byte of memory allocated by Malloc
  2695.  
  2696. Flags affected:        Carry=0 if no error.
  2697.                Carry=1 if insufficient memory.
  2698.  
  2699. Example of Usage:
  2700.                mov     cx, 256
  2701.                Malloc
  2702.                jnc     GoodMalloc
  2703.                print   db    "Insufficient memory to continue.",cr,lf,0
  2704.                jmp   Quit
  2705.       GoodMalloc:  mov   es:[di], 0          ;Init string to NULL
  2706.  
  2707.  
  2708. Description:  Malloc is the workhorse routine you use to allocate a block of
  2709.           memory.  You give it the number of bytes you need and if it
  2710.           finds a block large enough, it will  allocate the requested
  2711.           amount and return a pointer to that block.
  2712.  
  2713.           Most memory managers require  a small amount of overhead for each
  2714.           block they allocate.  Stdlib's (current) memory manager requires
  2715.           an overhead of eight bytes.  Furthermore, the grainularity is 16
  2716.           bytes.  This means that Malloc always allocates blocks of memory
  2717.           in paragraph multiples.  Therefore, Malloc may actually reserve
  2718.           more storage than you specify. Therefore, the value returned in
  2719.           CX may be somewhat greater than the requested value.  By setting
  2720.           the minimum allocation size to a paragraph, however, the
  2721.           overhead is reduced and the speed of Malloc is improved by a
  2722.           considerable amount.
  2723.  
  2724.           Stdlib's memory management does not do any garbage collection.
  2725.           Doing so would place too many demands on Malloc's users.
  2726.           Therefore, it is quite possible for you to fragment memory with
  2727.           multiple calls to maloc, realloc, and free.  You could wind up in
  2728.           a situation where there is enough free memory to satisfy your
  2729.           request, but there isn't a single contiguous block large enough
  2730.           for the request.  Malloc treats this as an insufficient memory
  2731.           error and returns with the carry flag set.
  2732.  
  2733.           If Malloc cannot allocate a block of the requested size, it
  2734.           returns with the carry flag set.  In this situation, the contents
  2735.           of ES:DI is undefined.  Attempting to dereference this pointer
  2736.           will produce erratic and, perhaps, disasterous results.
  2737.  
  2738. Include:              stdlib.a or memory.a
  2739.  
  2740.  
  2741. Routine:  Realloc
  2742. -----------------
  2743.  
  2744. Category:  Memory Management Routine
  2745.  
  2746. Registers on Entry:   CX - number of bytes to reserve
  2747.               ES:DI - pointer to block to  reallocate.
  2748.  
  2749. Registers on return:  CX - number of bytes actually reserved by Realloc.
  2750.               ES:DI - pointer to first byte of memory allocated by
  2751.                   Realloc.
  2752.  
  2753. Flags affected:       Carry = 0 if no error.
  2754.               Carry = 1 if insufficient memory.
  2755.  
  2756. Example of Usage:
  2757.             mov    cx, 1024    ;Change block size to 1K
  2758.             les    di, CurPtr    ;Get address of block into ES:DI
  2759.             realloc
  2760.             jc    BadRealloc
  2761.             mov    word ptr CurPtr, di
  2762.             mov    word ptr CurPtr+2, es
  2763.  
  2764.  
  2765. Description:  Realloc lets you change the size of an allocated block in the
  2766.           heap.  It allows you to make the block larger or smaller.
  2767.           If you make the  block smaller, Realloc simply frees (returns
  2768.           to the heap) any leftover bytes at the end of the block.  If
  2769.           you make the block larger, Realloc goes out and allocates a
  2770.           block of the requested size, copies the bytes form the old
  2771.           block to the beginning of the new block (leaving the bytes at
  2772.           the end of the new block uninitialized)), and then frees the
  2773.           old block.
  2774.  
  2775.  
  2776. Include:               stdlib.a or memory.a
  2777.  
  2778.  
  2779. Routine:  Free
  2780. --------------
  2781.  
  2782. Category:               Memory Management Routine
  2783.  
  2784. Registers on Entry:     ES:DI - pointer to block to deallocate
  2785.  
  2786. Registers on return:    None
  2787.  
  2788. Flags affected:         Carry = 0 if no error.
  2789.             Carry = 1 if ES:DI doesn't point at a Free block.
  2790.  
  2791. Example of Usage:
  2792.             les     di, HeapPtr
  2793.             Free
  2794.  
  2795. Description:  Free (possibly) deallocates storage allocated on the heap by
  2796.           malloc or Realloc.  Free returns this storage to heap so other
  2797.           code can reuse it later.  Note, however, that Free doesn't
  2798.           always return storage to the heap.  The memory manager data
  2799.           structure keeps track of the number of pointers currently
  2800.           pointing at a block on the heap (see DupPtr, below).  If you've
  2801.           set up several pointers such that they point at the same block,
  2802.           Free will not deallocate the storage until you've freed all of
  2803.           the pointers which point at the block.
  2804.  
  2805.           Free usually returns an error code (carry flag = 1) if you
  2806.           attempt to Free a block which is not currently allocated or if
  2807.           you pass it a memory address which was not returned by malloc
  2808.           (or Realloc).  By no means is this routine totally robust.
  2809.           If you start calling free with arbitrary pointers in es:di
  2810.           (which happen to be pointing into the heap) it is possible,
  2811.           under certain circumstances, to confuse Free and it will attempt
  2812.           to free a block it really should not.
  2813.  
  2814.           This problem could be solved by adding a large amount of extra
  2815.           code to the free routine, but it would slow it down considerably.
  2816.           Therefore, a little safety has been sacrificed for a lot of
  2817.           speed.  Just make sure your code is correct and everything will
  2818.           be fine!
  2819.  
  2820.  
  2821. Include:               stdlib.a or memory.a
  2822.  
  2823.  
  2824. Routine:  DupPtr
  2825. ----------------
  2826.  
  2827. Category:             Memory Manager Routine
  2828.  
  2829. Registers on Entry:   ES:DI - pointer to block
  2830.  
  2831. Registers on return:  None
  2832.  
  2833. Flags affected:       Carry = 0 if no error.
  2834.               Carry = 1 if es:di doesn't point at a free block.
  2835.  
  2836. Example of Usage:
  2837.               les     di,  Ptr
  2838.               DupPtr
  2839.  
  2840.  
  2841. Description:  DupPtr increments the pointer count for the block at the
  2842.           specifiied address.  Malloc sets this counter to one.  Free
  2843.           decrements it by one.  If free decrements the value and it
  2844.           becomes zero, free will release the storage to the heap for
  2845.           other use.  By using DupPtr you can tell the memory manager
  2846.           that you have several pointers pointing  at the same block
  2847.           and that it shouldn't deallocate the storage until you free
  2848.           all of those pointers.
  2849.  
  2850.  
  2851. Include:              stdlib.a or memory.a
  2852.  
  2853.  
  2854. Routine:  IsInHeap
  2855. ------------------
  2856.  
  2857. Category:             Memory Management Routine
  2858.  
  2859. Registers on Entry:   ES:DI - pointer to a block
  2860.  
  2861. Registers on return:  None
  2862.  
  2863. Flags affected:       Carry = 0 if ES:DI is a valid pointer.
  2864.               Carry = 1 if not.
  2865.  
  2866. Example of Usage:
  2867.             les    di, MemPtr
  2868.             IsInHeap
  2869.             jc    NotInHeap
  2870.  
  2871. Description:  This routine lets you know if es:di contains the address of
  2872.           a byte in the heap somewhere.  It does not tell you if es:di
  2873.           contains a valid pointer returned by malloc (see IsPtr, below).
  2874.           For example, if es:di contains the address of some particular
  2875.           element of an array (not necessarily the first element)
  2876.           allocated on the heap, IsInHeap will return with the carry clear
  2877.           denoting that the es:di points somewhere in the heap.  Keep in
  2878.           mind that calling this routine does not validate the pointer;
  2879.           it could be pointing at a byte which is part of the memory
  2880.           manager data structure rather than at actual data (since the
  2881.           memory manager maintains that informatnion within the
  2882.           bounds of the heap). This routine is mainly useful for seeing
  2883.           if something is allocated on the heap as opposed to somewhere
  2884.           else (like your code, data, or stack segment).
  2885.  
  2886.  
  2887. Include:              stdlib.a or memory.a
  2888.  
  2889. Routine:  IsPtr
  2890. ---------------
  2891.  
  2892. Category:               Memory Management Routine
  2893.  
  2894. Registers on Entry:     ES:DI - pointer to block
  2895.  
  2896. Registers on return:    None
  2897.  
  2898. Flags affected:         Carry = 0 if es:di is a valid pointer.
  2899.             Carry = 1 if not.
  2900.  
  2901. Example of Usage:
  2902.             les    di, MemPtr
  2903.             IsPtr
  2904.             jc    NotAPtr
  2905.  
  2906.  
  2907.  
  2908. Description:  IsPtr is much more specific than IsInHeap.  This routine returns
  2909.           the carry flag clear if and only if es:di contains the address
  2910.           of a properly allocated (and currently allocated) block on the
  2911.           heap.  This pointer must be a value returned by Malloc, Realloc,
  2912.           or DupPtr and that block must be currently allocated for IsPtr
  2913.           to return the carry flag clear.
  2914.  
  2915.  
  2916. Include:                stdlib.a or memory.a
  2917.  
  2918. Routine:  BlockSize
  2919. -------------------
  2920.  
  2921. Category:               Memory Management Routine
  2922.  
  2923. Registers on Entry:     ES:DI - pointer to block
  2924.  
  2925. Registers on return:    CX-    Size of specifed block (in bytes). Returns
  2926.                 zero if ES:DI does not point at a legal block.
  2927.  
  2928. Flags affected:        None
  2929.  
  2930. Example of Usage:
  2931.             les    di, MemPtr
  2932.             BlockSize
  2933.  
  2934.  
  2935.  
  2936. Description:
  2937.  
  2938. BlockSize returns the size (in bytes) of a block allocated on the heap.
  2939. If the block is not in the heap, this code returns zero in CX.
  2940. This routine does NOT verify that the block was actually allocated and
  2941. is still allocated.  It just makes sure that the pointer points at a valid
  2942. location somewhere in the heap and returns the block size from the data
  2943. structure at the specified address.  You are responsible for ensuring that
  2944. you do not use a deallocated memory block.
  2945.  
  2946. Include:                stdlib.a or memory.a
  2947.  
  2948. Routine:  MemAvail
  2949. ------------------
  2950.  
  2951. Category:               Memory Management Routine
  2952.  
  2953. Registers on Entry:     None
  2954.  
  2955. Registers on return:    CX-    Size of largest free block on the heap
  2956. Flags affected:        None
  2957.  
  2958. Example of Usage:
  2959.             MemAvail
  2960.  
  2961.  
  2962.  
  2963. Description:
  2964.  
  2965. MemAvail returns the size (in paragraphs) of the largest free block on the
  2966. heap.  You can use this call to determine if there is sufficient storage
  2967. for an object on the heap.
  2968.  
  2969. Include:                stdlib.a or memory.a
  2970.  
  2971. Routine:  MemFree
  2972. -----------------
  2973.  
  2974. Category:               Memory Management Routine
  2975.  
  2976. Registers on Entry:     None
  2977.  
  2978. Registers on return:    CX-    Size of all free blocks on the heap.
  2979. Flags affected:        None
  2980.  
  2981. Example of Usage:
  2982.             MemFree
  2983.  
  2984.  
  2985.  
  2986. Description:
  2987.  
  2988. MemFree returns the size (in paragraphs) of the the free storage on the
  2989. heap.  Note that this storage might be fragmented and not all of it may
  2990. be available for use by Malloc.  To determine the largest free block
  2991. available use MemAvail.
  2992.  
  2993. Include:                stdlib.a or memory.a
  2994. Process Manager Routines
  2995. ------------------------
  2996.  
  2997. The UCR Standard Library Process package provides a simple preemptive
  2998. multitasking package for 8086 assembly language programmers.  It also
  2999. provides a coroutine package and support for semaphores.
  3000.  
  3001. First,  *AND THIS IS VERY IMPORTANT*, this package only supports the
  3002. 8086, 8088, 80188, 80186, and 80286 processors operating in real mode.
  3003. You will need to make some minor modifications to the process package if
  3004. you wish to support the 32-bit x86 processors.  The current process manager
  3005. only saves 16-bit registers, not the 32-bit registers of the 80386 and later.
  3006. You will, however, find it a relatively minor task to go in and modify this
  3007. code to support the 386 and later processors.  We will probably add support
  3008. for these processors at a later date when time allows.
  3009.  
  3010. Second, *THIS IS ALSO VERY IMPORTANT*, keep in mind that DOS, BIOS, and many
  3011. of the routines in the standard library ARE NOT REENTRANT. Two processes
  3012. executing at the (apparent) same time cannot both be executing DOS, BIOS, or
  3013. the same standard library routines.  It is unlikely that DOS or BIOS will
  3014. ever be made reentrant, and you shouldn't ever expect the standard library
  3015. to be made reentrant (far too much work).  The standard library provides
  3016. semaphore support through which you can control access to critical resources
  3017. including DOS, BIOS, and the UCR Standard Library.  If you are unfamiliar
  3018. with terms like reentrancy, semaphores, synchronization, and deadlock, you
  3019. should probably pick up a good text on operating systems and familiarize
  3020. yourself with these terms before attempting to use this package.
  3021.  
  3022. This process package provides three facilities to your assembly language
  3023. programs: A preemptive multitasking process manager, coroutine support, and
  3024. semaphore support.  There are six routines associated with the preemptive
  3025. multitasking system: PRCSINIT, PRCSQUIT, FORK, KILL, DIE, and YIELD.  There
  3026. are three routines associated with the coroutines package: COINIT, COCALL,
  3027. and COCALLL (though you'll rarely refer to COCALLL directly).  Finally, there
  3028. are two routines to support semaphores: WAITSEMAPH and RLSSEMAPH.
  3029.  
  3030. The PRCSINIT and PRCSQUIT routines initialize and deinitialize the interrupt
  3031. system for the multitasking system.  You must call PRCSINIT prior to
  3032. executing any of the preemptive multitasking routines or any of the semaphore
  3033. routines (the semaphore routines make sense only in the context of preemptive
  3034. multitasking).  This initializes various internal variables and patches the
  3035. INT 8 interrupt vector (timer interrupt) to point at an internal routine
  3036. in the process manager.  You must call PRCSQUIT when you are done with the
  3037. preemptive multitasking system; certainly you must call it before your
  3038. program terminates *FOR ANY REASON*.  If you do not call PRCSQUIT, the system
  3039. will probably crash shortly after you try anything else after returning to
  3040. DOS since the timer interrupt will still be calling the routine left in
  3041. memory when your program terminates.
  3042.  
  3043. The process manager patches into the 1/18th second clock on the PC.  There-
  3044. fore, the system will automatically perform an context switch every 55ms
  3045. or so.  If your application reprograms the timer chip, this may produce
  3046. unexpected results.  This may be particularly bothersome if you are running
  3047. a TSR which plays with the timer chip.  Absolutely no attempt was made to
  3048. make this code robust enough to work in all cases with other code which
  3049. ties into the timer interrupt.  Most well-written code will work fine, but
  3050. there are not guarantees.
  3051.  
  3052. The FORK routine lets you spawn a new process.  For each call to FORK your
  3053. code makes, the FORK routine returns twice- once as the parent process and
  3054. once as the child process.  FORK returns process ID information in the AX
  3055. and BX registers so that the code immediately following the FORK can figure
  3056. out if it's the parent or child process.  FORK provides the basic (and only!)
  3057. mechanism for starting a second process.
  3058.  
  3059. The KILL and DIE routines let you terminate a process.  KILL lets one process
  3060. terminate some other process (generally a child process).  DIE lets a
  3061. process terminate itself.
  3062.  
  3063. The YIELD routine gives up the current process' time slice and lets some other
  3064. process take over.
  3065.  
  3066. The semaphore routines, WaitSemaph and RlsSemaph, let you wait on a semaphore
  3067. or signal that semaphore, respectively.  The PROCESS.A and PROCESS.A6
  3068. include files contain the definition of a semaphore type, it is
  3069.  
  3070.         semaphore    struc
  3071.         SemaCnt        dw    1
  3072.         smaphrLst    dd    ?
  3073.         endsmaphrlst    dd    ?
  3074.         semaphore    ends
  3075.  
  3076. The only field you should ever play around with is the SemaCnt field.  This
  3077. value is the number of processes which are allowed to be in the critical
  3078. region controlled by the semaphore at one time.  For most mutual exclusion
  3079. problems, this value should always be one.  Do not modify this value once
  3080. the program starts running.  The process package increments and decrements
  3081. this number to keep track of the number of processes waiting to use a
  3082. resource.  If you want to allow two processes to share a resource at the
  3083. same time, you should declare your semaphore variable as follows:
  3084.  
  3085.         MySemaPh    semaphore    <2>
  3086.  
  3087. You execute the WaitSemaPh routine to see if a semaphore is currently busy.
  3088. When you get back from the WaitSemaPh call, the resource protected by the
  3089. semaphore is exclusively yours until you execute the RlsSemaPh routine.
  3090. Note that when you call the WaitSemaPh routine, the specified resource may
  3091. already be in use, in which case your process will be suspended until the
  3092. resource is freed (and anyone waiting in line ahead of you has had their
  3093. shot at the resource).  If you do not call the RlsSemaPh routine to free
  3094. the semaphore, any other process waiting on that resource will wait
  3095. indefinitely.  Also note that if you call WaitSemaPh twice on a semaphore
  3096. without releasing it inbetween, your process and any other process which
  3097. waits on that resource will deadlock.
  3098.  
  3099. While semaphores solve a large number of synchronization and mutual exclusion
  3100. problems, their primary use in the UCR Standard Library is to prevent re-
  3101. entrancy problems in DOS, BIOS, and the Standard Library itself.  For example,
  3102. if you have two processes which print values to the display, attempting to
  3103. run both processes concurrently will crash the system if they both attempt
  3104. to print at the same time (since this will cause DOS to be reentered).  A
  3105. simple solution is to use a DOS semaphore as follows:
  3106.  
  3107. In the data segment:
  3108.  
  3109. DOS        semaphore    {}
  3110.  
  3111. In Process 1:
  3112.  
  3113.         lesi    DOS
  3114.         WaitSemaPh
  3115.         print
  3116.         db    "Printed from process #1.",cr,lf,0
  3117.         lesi    DOS
  3118.         RlsSemaPh
  3119.  
  3120. In Process 2:
  3121.  
  3122.         lesi    DOS
  3123.         WaitSemaPh
  3124.         print
  3125.         db    "Printed from process #2.",cr,lf,0
  3126.         lesi    DOS
  3127.         RlsSemaPh
  3128.  
  3129. Semaphore guarantee mutual exclusion between the WaitSemaPh and RlsSemaPh
  3130. calls (for a particular semaphore variable, DOS in this case).  Hence, once
  3131. process #1 enters its *CRITICAL REGION* by executing the WaitSemaPh call,
  3132. any attempt by process two to enter its critical region will cause process
  3133. two to suspend execution until process one executes the RlsSemaPh routine.
  3134.  
  3135. Coroutines provide "simulated" multitasking where the processes themselves
  3136. determine when to perform a context switch.  This is quite similar to the
  3137. "cooperative multitasking" systems provided by Apple, Microsoft, and others
  3138. ("cooperative multitasking" is a hyped up term to hide the fact that their
  3139. systems provide only multiprogramming, not multitasking).  There are many
  3140. advantages and disadvantages to coroutines vs. multitasking.  First of all,
  3141. reentrancy problems do not exist in a system using coroutines.  Since you
  3142. control when one process switches to another, you can make sure that such
  3143. context switches do not occur in critical regions.  Another advantage to
  3144. coroutines is that the processes themselves can determine which other process
  3145. gets the next access to the CPU.  Finally, when a coroutine is executing,
  3146. it gets full access to the CPU to handle a time-critical operation without
  3147. fear of being preempted.  On the other hand, poorly designed coroutines
  3148. provide a very crude approximation to multitasking and may actually hurt
  3149. the overall performance of the system.
  3150.  
  3151. The UCR Standard Library provides three routines to support coroutines:
  3152. COINIT, COCALL, and COCALLL.  Generally, you'll only see COINIT and COCALL
  3153. in a program, the standard library automatically generates COCALLL calls
  3154. for certain types of COCALL statements.  The COINIT routine initializes the
  3155. coroutine package and creates a process control block (PCB) for the currently
  3156. active routine.  COCALL switches context to some other process.  When one
  3157. process COCALLs another and that second process COCALLs the first, the first
  3158. process continues execution immediately after the first COCALL instruction
  3159. (so it behaves more like a return than a call).  In general, you should not
  3160. think of COCALL as a "call" but rather as a "switch to some other process."
  3161.  
  3162. You may have coroutines and multitasking active at the same time, but you
  3163. should not make a COCALL to a process which is being time-sliced by the
  3164. multitasking system.  I won't guarantee that this *won't* work, but it
  3165. seems sufficiently weird that something is bound to go wrong.
  3166.  
  3167. For those who are interested, the coroutine and multitasking packages
  3168. maintain the state of a process in a process control block (PCB) which
  3169. is the following structure:
  3170.  
  3171.  
  3172.  
  3173.         pcb        struc
  3174.         NextProc    dd    ?
  3175.         regsp        dw    ?
  3176.         regss        dw    ?
  3177.         regip        dw    ?
  3178.         regcs        dw    ?
  3179.  
  3180.         regax        dw    ?
  3181.         regbx        dw    ?
  3182.         regcx        dw    ?
  3183.         regdx        dw    ?
  3184.         regsi        dw    ?
  3185.         regdi        dw    ?
  3186.         regbp        dw    ?
  3187.         regds        dw    ?
  3188.         reges        dw    ?
  3189.         regflags    dw    ?
  3190.         PrcsID        dw    ?
  3191.         StartingTime    dd    ?
  3192.         StartingDate    dd    ?
  3193.         CPUTime        dd    ?
  3194.         pcb        ends
  3195.  
  3196. As mentioned earlier, this code does not maintain the full state of the
  3197. 80386 and later processors since it only saves the 16-bit register set.
  3198. If you like, you can easily change the definition of the PCB, and all the
  3199. code in the PROCESS.ASM file which refers to the PCB, and support full
  3200. 32-bit operation.  As usual, you should rarely, if ever, play around with
  3201. the internal fields of a PCB.  That is for the process manager to do and you
  3202. could mess things up pretty back if you're not careful.
  3203.  
  3204. Routine: prcsinit
  3205. -----------------
  3206.  
  3207. Category:             Processes
  3208.  
  3209. Registers on entry:   None
  3210.  
  3211. Registers on return:  None
  3212.  
  3213. Flags affected:       None
  3214.  
  3215. Example of Usage:
  3216.  
  3217.             prcsinit
  3218.  
  3219.  
  3220. Description:
  3221.  
  3222. Prcsinit initializes the process manager.  Note that if you make a call to
  3223. the process manager, you *MUST* make a call to prcsquit before your program
  3224. quits.  Failure to do so will crash the system in short order.  Note that
  3225. you must even handle the case where the user types control-C or encounters
  3226. a critical error and aborts back to DOS.
  3227.  
  3228. This routine patches into the timer interrupt vector (INT 08) and may not
  3229. work properly with code in the system which is also messing around with the
  3230. timer interrupt.
  3231.  
  3232. Include:    stdlib.a or process.a
  3233.  
  3234. Routine: prcsquit
  3235. -----------------
  3236.  
  3237. Category:             Processes
  3238.  
  3239. Registers on entry:   None
  3240.  
  3241. Registers on return:  None
  3242.  
  3243. Flags affected:       None
  3244.  
  3245. Example of Usage:
  3246.  
  3247.             prcsquit
  3248.  
  3249.  
  3250. Description:
  3251.  
  3252. Prcsquit deinitializes the process manager.  It detaches the timer interrupt
  3253. from the internal routine and performs various other clean up chores.  You
  3254. must call this routine before your program terminates if you've called
  3255. prcsinit somewhere in your program.
  3256.  
  3257. Note that you cannot call prcsquit twice in a row, although you can call
  3258. the prcsinit/prcsquit combinations as many times as you like in your code.
  3259.  
  3260. Include:    stdlib.a or process.a
  3261.  
  3262. Routine: fork
  3263. -------------
  3264.  
  3265. Category:             Processes
  3266.  
  3267. Registers on entry:       ES:DI-    Points at a PCB to hold the process info
  3268.                 for the new process.  The regss and regsp
  3269.                 fields of this PCB must be initialized to
  3270.                 the top of a new stack for the new process.
  3271.  
  3272. Registers on return:      AX-    <Parent process> Returned containing zero.
  3273.                 <Child  process> Child process ID.
  3274.  
  3275.             BX-     <Parent process> Child's process ID.
  3276.                 <Child  process> Returned containing zero.
  3277.  
  3278. Flags affected:           None
  3279.  
  3280. Example of Usage:
  3281.  
  3282. ChildPCB        pcb    {0, offset endstk, seg endstk}
  3283.              .
  3284.              .
  3285.              .
  3286.  
  3287.             lesi    ChildPCB
  3288.             fork
  3289.             cmp    ax, 0
  3290.             jne    DoChildProcess
  3291.             <Parent process continues here>
  3292.              .
  3293.              .
  3294.              .
  3295. ChildsStack        db    1024 dup (?)
  3296. EndStk            dw    0
  3297.  
  3298.  
  3299.  
  3300. Description:
  3301.  
  3302. Fork spawns a new process.  You make a single call to fork but it returns
  3303. twice- once for the parent process (the original caller to fork) and once
  3304. for the child process (the new process created by fork).  On entry to fork
  3305. ES:DI must point at a PCB for the new process which has the REGSP and
  3306. REGSS fields initialized to point at the last word in a stack set aside for
  3307. the child process.  *THIS IS VERY IMPORTANT!*
  3308.  
  3309. On return, the code following the call to FORK can test to see whether the
  3310. parent is returning or the child is returning by looking at the value in
  3311. the AX register.  AX will contain zero upon return to the parent process.
  3312. It will contain a non-zero value, which is the process ID, when returning
  3313. to the child process.  When the parent process returns, FORK returns the
  3314. process ID of the child process in the BX register.  The parent process can
  3315. use this value to kill the child process, should that become necessary later
  3316. on.  If the child needs access to the parent's process ID, the parent process
  3317. should store away its process ID in a variable before calling the FORK
  3318. routine.  Note that with the exception of the AX, BX, SP, and SS registers,
  3319. FORK preserves all register values and returns the same set of values to both
  3320. the parent and child processes.  In particular, it preserves the value of
  3321. the DS register so the child will have access to any global variables in
  3322. use by the parent process.
  3323.  
  3324. FORK does *not* copy the parent's stack data to the child's stack.  Upon
  3325. return from FORK, the child's stack is empty.  If you call FORK after
  3326. pushing something on the stack (e.g., a return address because you've called
  3327. FORK inside some other procedure), that information will not be placed on the
  3328. stack of the child process.  If you such information pushed on the child's
  3329. stack, you will need to save SS:SP prior to calling FORK (in a global
  3330. variable) and then push the data pointed at by this saved value onto the
  3331. child's stack upon return.  Of course, it's a whole lot easier if you simply
  3332. don't count on anything being on the child's stack when you get back from
  3333. FORK.  In particular, don't call FORK from inside some nested routine and
  3334. expect the child process to return to the caller of the routine containing
  3335. FORK.
  3336.  
  3337. Include:    stdlib.a or process.a
  3338.  
  3339. Routine: die
  3340. ------------
  3341.  
  3342. Category:             Processes
  3343.  
  3344. Registers on entry:   None
  3345.  
  3346. Registers on return:  None
  3347.  
  3348. Flags affected:       None
  3349.  
  3350. Example of Usage:
  3351.  
  3352.             die
  3353.  
  3354. Description:
  3355.  
  3356. Die kills the current process.  Control is transferred to some other process
  3357. in the process manager's ready-to-run queue.  Control never returns back to
  3358. the current process.
  3359.  
  3360. Note: if the current process is the only process running, calling DIE may
  3361. crash the system.
  3362.  
  3363. Include:    stdlib.a or process.a
  3364.  
  3365. Routine: kill
  3366. -------------
  3367.  
  3368. Category:                 Processes
  3369.  
  3370. Registers on entry:       AX-    Process ID of process to terminate.
  3371.  
  3372. Registers on return:      None
  3373.  
  3374. Flags affected:           None
  3375.  
  3376. Example of Usage:
  3377.  
  3378.             mov    ax, ProcessID
  3379.             kill
  3380.  
  3381. Description:
  3382.  
  3383. KILL lets one process terminate another.  Typically, a parent might kill a
  3384. child process, although any process which knows the process ID of some other
  3385. process can kill that other process.
  3386.  
  3387. If a process passes its own ID to KILL, the system behaves exactly as though
  3388. the process called the DIE routine.
  3389.  
  3390. If a process passes its own ID to KILL and it is the only process in the
  3391. system, the system may crash.
  3392.  
  3393. Include:    stdlib.a or process.a
  3394.  
  3395. Routine: yield
  3396. --------------
  3397.  
  3398. Category:                 Processes
  3399.  
  3400. Registers on entry:       None
  3401.  
  3402. Registers on return:      None
  3403.  
  3404. Flags affected:           None
  3405.  
  3406. Example of Usage:
  3407.  
  3408.             yield
  3409.  
  3410. Description:
  3411.  
  3412. YIELD voluntarily gives up the CPU.  The remainder of the current time slice
  3413. is given to some other process and the current process goes to the end of the
  3414. process manager's ready to run queue.  This call is particularly useful for
  3415. passing control between two cooperating process where one process needs to
  3416. wait for some action to complete and you don't feel like using semaphores
  3417. to synchronize the two activies.  This call is roughly equivalent to
  3418. "COCALL <next available process>".
  3419.  
  3420. Include:    stdlib.a or process.a
  3421.  
  3422. Routine: coinit
  3423. ---------------
  3424.  
  3425. Category:                 Processes
  3426.  
  3427. Registers on entry:       ES:DI-    Points at an empty PCB for the current process.
  3428.  
  3429. Registers on return:      None
  3430.  
  3431. Flags affected:           None
  3432.  
  3433. Example of Usage:
  3434.  
  3435. MainProcess        pcb    {}
  3436.              .
  3437.              .
  3438.              .
  3439.             lesi    MainProcess
  3440.             coinit
  3441.  
  3442.  
  3443. Description:
  3444.  
  3445. COINIT initializes the coroutine package and sets up an internal pointer
  3446. to the PCB specified by ES:DI (the "current coroutine" pcb).  On the next
  3447. COCALL, the process state will be saved in the pcb you've specified on the
  3448. COINIT call.  Note that you do not have to initialize this pcb in any way,
  3449. that will all be taken care of by COINIT and the COCALL.
  3450.  
  3451. Include:    stdlib.a or process.a
  3452.  
  3453. Routine: cocall/cocalll
  3454. -----------------------
  3455.  
  3456. Category:                 Processes
  3457.  
  3458. Registers on entry:       ES:DI-    Points at a PCB for the new coroutine
  3459.                 (COCALL only).
  3460.             CS:IP-    Points at a pointer to a PCB for the new
  3461.                 coroutine (COCALLL only).
  3462.  
  3463. Registers on return:      None
  3464.  
  3465. Flags affected:           None
  3466.  
  3467. Example of Usage:
  3468.  
  3469. OtherProcess        pcb    {----}
  3470. YetAnotherProcess    pcb    {----}
  3471.              .
  3472.              .
  3473.              .
  3474.             lesi    OtherProcess
  3475.             cocall
  3476.              .
  3477.              .
  3478.              .
  3479.             cocall    YetAnotherProcess
  3480.  
  3481. Description:
  3482.  
  3483. COCALL switches context between two coroutines.  There are two versions of
  3484. this call, although you use COCALL to invoke both of them: COCALL and COCALLL.
  3485. For COCALL, you must pass the address of a PCB in ES:DI.  When calling COCALL
  3486. in this fashion, the operand field of the COCALL instruction must be blank
  3487. (see the example above).  COCALLL expects the address of the pcb to follow
  3488. in the code stream.  The COCALL macro looks for an operand and, if one is
  3489. present, it automatically creates the appropriate call to COCALLL and inserts
  3490. the address of the PCB in the code stream (again, see the example above).
  3491.  
  3492. Before you start a coroutine for the first time by calling COCALL, you must
  3493. properly initialize the pcb for that coroutine.  You must provide initial
  3494. values for the regsp, regss, regip, and regcs fields of the pcb (fields two
  3495. through five in the pcb structure).  Regsp and regss must point at the last
  3496. word of an appropriately sized stack for that coroutine; regip and regcs
  3497. must point at the initial entry point for the coroutine.  For example, if you
  3498. want to switch between the current process and a coroutine named "CORTN", you
  3499. could use the following code:
  3500.  
  3501. MainCoRtn    pcb    {}
  3502. CoRtnPCB    pcb    {0,offset CoRtnStk, seg CoRtnStk,
  3503.                         offset CoRtn, seg CoRtn}
  3504.          .
  3505.          .
  3506.          .
  3507.         lesi    MainCoRtn
  3508.         coinit
  3509.          .
  3510.          .
  3511.          .
  3512.         cocall    CoRtnPCB
  3513.          .
  3514.          .
  3515.          .
  3516. CoRtn        proc
  3517.          .
  3518.          .
  3519.          .
  3520.         cocall    MainCoRtn
  3521.          .
  3522.          .
  3523.          .
  3524. CoRtn        endp
  3525.          .
  3526.          .
  3527.          .
  3528.         db    1024 dup (?)
  3529. CoRtnStk    dw    0
  3530.  
  3531.  
  3532. Include:    stdlib.a or process.a
  3533.  
  3534. Routine: waitsemaph
  3535. -------------------
  3536.  
  3537. Category:                 Processes
  3538.  
  3539. Registers on entry:       ES:DI-    Points at a semaphore variable
  3540.  
  3541. Registers on return:      None
  3542.  
  3543. Flags affected:           None
  3544.  
  3545. Example of Usage:
  3546.  
  3547. DOSsemaph        semaphore    {}
  3548.              .
  3549.              .
  3550.              .
  3551.             lesi    DOSsemaph
  3552.             WaitSemaPh
  3553.              .
  3554.              . <This is the critical section>
  3555.              .
  3556.             lesi    DOSsemaph
  3557.             RlsSemaPh
  3558.  
  3559. Description:
  3560.  
  3561. WaitSemaPh and RlsSemaPh protect critical regions in a multitasking
  3562. environment. WaitSemaPh expects you to pass the address of a semaphore
  3563. variable in ES:DI.  If that particular semaphore is not currently in use,
  3564. WaitSemaPh marks the semaphore "in use" and immediately returns.  If the
  3565. semaphore is already in use, the WaitSemaPh queues up the current process
  3566. on a waiting queue and lets some other process start running.  Once a process
  3567. is done with the resource protected by a semaphore, it must call RlsSemaPh
  3568. to release the semaphore back to the system.  If any processes are waiting
  3569. on that semaphore, the call to RlsSemaPh will activate the first such process.
  3570. Note that a process must not make two successive calls to WaitSemaPh on a
  3571. particular semaphore variable without calling RlsSemaPh between the calls.
  3572. Doing so will cause a deadlock.
  3573.  
  3574. Include:    stdlib.a or process.a
  3575.  
  3576. Routine: rlssemaph
  3577. ------------------
  3578.  
  3579. Category:                 Processes
  3580.  
  3581. Registers on entry:       ES:DI-    Points at a semaphore variable
  3582.  
  3583. Registers on return:      None
  3584.  
  3585. Flags affected:           None
  3586.  
  3587. Example of Usage:    See WaitSemaPh
  3588.  
  3589. Description:
  3590.  
  3591. RlsSemaPh releases a semaphore (also known as "signalling") that the current
  3592. process has aquired via a call to WaitSemaPh.  Please see the WaitSemaPh
  3593. explaination for more details.  You should not call RlsSemaPh without first
  3594. calling WaitSemaPh.  Doing so may cause some inconsistencies in the system.
  3595.  
  3596. Include:    stdlib.a or process.a
  3597.  
  3598. Interrupt-Driven Serial Port I/O Package
  3599. ========================================
  3600.  
  3601. One major problem the the PC's BIOS is the lack of good interrupt driven
  3602. I/O support for the serial port.  The BIOS provides a mediocre set of polled
  3603. I/O facilities, but completely drops the ball on interrupt driven I/O.
  3604.  
  3605. This set of routines in the standard library provides polled I/O support
  3606. to read and set the registers on the 8250 (or other comparable chip, e.g.,
  3607. 16450) as well as read and write data (polled).  In addition, there are
  3608. a pair of routines to initialize and disable the interrupt system as well
  3609. as perform I/O using interrupts.
  3610.  
  3611. Typical polled I/O session:
  3612.  
  3613. 1. Initialize chip using polled I/O routines.
  3614. 2. Read and write data using ComRead and ComWrite routines.
  3615.  
  3616. Typical interrupt driven I/O session:
  3617.  
  3618. 1. Initialize chip using polled I/O routines.
  3619. 2. Read and write data using ComIn and ComOut routines.
  3620.  
  3621. Of course, all the details of serial communications cannot be discussed
  3622. here- it's far too broad a subject.  These routines, like most in the
  3623. library, assume you know what you're doing.  They just make it a little
  3624. easier on you.  If you don't understand anything about serial communications,
  3625. you *might* be able to use these routines, but they were not written with
  3626. that audience in mind.  There are several good references on serial communi-
  3627. cations; "C Programmer's Guide to Serial Communications" comes to mind.  If
  3628. you've never looked at the 8250 or comparable chips before, you might want
  3629. to take a look at a reference such as this one if the routines in this
  3630. section don't make much sense.
  3631.  
  3632. Note: This routines are set up to use the COM1: hardware port.  See the
  3633. source listings if you want to access a different serial port.  Perhaps in
  3634. a future release we will modify this code to work with any serial port.
  3635.  
  3636.  
  3637. Routine:  ComBaud
  3638. -----------------
  3639.  
  3640. Author:                  Randall Hyde
  3641.  
  3642. Category:        Serial Communications
  3643.  
  3644. Registers on entry:       AX-    BPS (baud rate): 110, 150, 300, 600, 1200,
  3645.                          2400, 4800, 9600, 19200
  3646.  
  3647. Registers on return:      None
  3648.  
  3649. Flags affected:           None
  3650.  
  3651. Example of Usage:
  3652.             mov    ax, 9600    ;Set system to 9600 bps
  3653.             ComBaud
  3654. Description:
  3655.  
  3656. ComBaud programs the serial chip to change its "baud rate" (technically,
  3657. it's "bits per second" not baud rate).  You load AX with the appropriate
  3658. bps value and call ComBaud, as above.  Note: if AX is not one of the legal
  3659. values, ComBaud defaults to 19.2kbps.
  3660.  
  3661. Include:    ser.a or stdlib.a
  3662.  
  3663. Routine:  ComStop
  3664. -----------------
  3665.  
  3666. Author:                  Randall Hyde
  3667.  
  3668. Category:                 Serial Communications
  3669.  
  3670. Registers on entry:       AX-    # of stop bits (1 or 2)
  3671.  
  3672. Registers on return:      None
  3673.  
  3674. Flags affected:           None
  3675.  
  3676. Example of Usage:
  3677.             mov    ax, 2        ;Set system to send 2 stop bits
  3678.             ComStop
  3679. Description:
  3680.  
  3681. ComStop programs the serial chip to transmit the specifed number of stop
  3682. bits when sending data.  You load AX with the appropriate value and call
  3683. ComStop, as above.  Note that this only affects the output data stream. The
  3684. serial chip on the PC will always work with one incoming stop bit, regardless
  3685. of the setting.  Since additional stop bits slow down your data transmission
  3686. (by about 10%) and most devices work fine with one stop bit, you should
  3687. normally program the chip with one stop bit unless you encounter some
  3688. difficulties.  The setting of this value depends mostly on the system you
  3689. are connecting to.
  3690.  
  3691. Include:    ser.a or stdlib.a
  3692.  
  3693. Routine:  ComSize
  3694. -----------------
  3695.  
  3696. Author:                  Randall Hyde
  3697.  
  3698. Category:                 Serial Communications
  3699.  
  3700. Registers on entry:       AX-    # of data bits to transmit (5, 6, 7, or 8)
  3701.  
  3702. Registers on return:      None
  3703.  
  3704. Flags affected:           None
  3705.  
  3706. Example of Usage:
  3707.             mov    ax, 8    ;Set system to send 8 data bits
  3708.             ComSize
  3709. Description:
  3710.  
  3711. ComSize programs the serial chip to transmit the specifed number of data
  3712. bits when sending data.  You load AX with the appropriate value and call
  3713. ComSize, as above.  The setting of this value depends mostly on the system
  3714. you are connecting to.
  3715.  
  3716. Include:    ser.a or stdlib.a
  3717.  
  3718. Routine:  ComParity
  3719. -------------------
  3720.  
  3721. Author:                  Randall Hyde
  3722.  
  3723. Category:                 Serial Communications
  3724.  
  3725. Registers on entry:       AX-    Bits 0, 1, and 2 are defined as follows:
  3726.                    bit 0- 1 to enable parity, 0 to disable.
  3727.                    bit 1- 0 for odd parity, 1 for even.
  3728.                    bit 2- Stuck parity bit.  If 1 and bit 0 is 1, then the parity bit
  3729.                       is always set to the inverse of bit 1.
  3730.  
  3731. Registers on return:      None
  3732.  
  3733. Flags affected:           None
  3734.  
  3735. Example of Usage:
  3736.             mov    ax, 0    ;Set NO parity
  3737.             ComParity
  3738.              .
  3739.              .
  3740.              .
  3741.             mov    ax, 11b    ;Set even parity
  3742.             ComParity
  3743. Description:
  3744.  
  3745. ComParity programs the serial chip to use various forms of parity error
  3746. checking.  If bit zero of AX is zero, then this routine disables parity
  3747. checking and transmission.  In this case, ComParity ignores the other
  3748. two bits (actually, the 8250 ignores them, ComParity just passes them
  3749. through).  If bit zero is a one, and bit two is a zero, then bit #1
  3750. defines even/odd parity during transmission and receiving.  If bit #0
  3751. is a one and bit two is a one, then the 8250 will always transmit bit #1
  3752. as the parity bit (forced on or off).
  3753.  
  3754. Include:    ser.a or stdlib.a
  3755.  
  3756. Routine:  ComRead
  3757. -----------------
  3758.  
  3759. Author:                  Randall Hyde
  3760.  
  3761. Category:                 Serial Communications
  3762.  
  3763. Registers on entry:       None
  3764.  
  3765. Registers on return:      AL-    Character read from port
  3766.  
  3767. Flags affected:           None
  3768.  
  3769. Example of Usage:
  3770.             ComRead
  3771.             mov    Buffer, al
  3772.  
  3773. Description:
  3774.  
  3775. ComRead polls the port to see if a character is available in the on-chip
  3776. data register.  If not, it waits until a character is available.  Once
  3777. a character is available, ComRead reads it and returns this character in
  3778. the AL register.
  3779.  
  3780. Warning: do *not* use this routine while operating in the interrupt mode.
  3781. This routine is for polled I/O only.
  3782.  
  3783. Include:    ser.a or stdlib.a
  3784.  
  3785. Routine:  ComWrite
  3786. ------------------
  3787.  
  3788. Author:                  Randall Hyde
  3789.  
  3790. Category:                 Serial Communications
  3791.  
  3792. Registers on entry:       AL-    Character to write to port
  3793.  
  3794. Registers on return:      None
  3795.  
  3796. Flags affected:           None
  3797.  
  3798. Example of Usage:
  3799.             mov    al, 'a'
  3800.             ComWrite
  3801.  
  3802. Description:
  3803.  
  3804. ComWrite polls the port to see if the transmitter is busy.  If so, it waits
  3805. until the current transmission is through.  Once the 8250 is done with the
  3806. current character, ComWrite will put the character in AL into the 8250
  3807. transmit register.
  3808.  
  3809. Warning: do *not* use this routine while operating in the interrupt mode.
  3810. This routine is for polled I/O only.
  3811.  
  3812. Include:    ser.a or stdlib.a
  3813.  
  3814. Routine:  ComTstIn
  3815. ------------------
  3816.  
  3817. Author:                  Randall Hyde
  3818.  
  3819. Category:                 Serial Communications
  3820.  
  3821. Registers on entry:       None
  3822.  
  3823. Registers on return:      AL=0 if no char available, 1 if char available
  3824.  
  3825. Flags affected:           None
  3826.  
  3827. Example of Usage:
  3828.  
  3829.         Wait4Data:    ComTstIn
  3830.                 cmp    al, 0
  3831.                 je    Wait4Data
  3832.  
  3833. Description:
  3834.  
  3835. ComTstIn polls the port to see if any input data is available.  If so,
  3836. it returns a one in AL, else it returns a zero.
  3837.  
  3838. Warning: do *not* use this routine while operating in the interrupt mode.
  3839. This routine is for polled I/O only.
  3840.  
  3841. Include:    ser.a or stdlib.a
  3842.  
  3843. Routine:  ComTstOut
  3844. -------------------
  3845.  
  3846. Author:                  Randall Hyde
  3847.  
  3848. Category:                 Serial Communications
  3849.  
  3850. Registers on entry:       None
  3851.  
  3852. Registers on return:      AL = 1 if xmitr available, 0 if not
  3853.  
  3854. Flags affected:           None
  3855.  
  3856. Example of Usage:
  3857.  
  3858.         WriteData:    <Do Something>
  3859.                 ComTstOut
  3860.                 cmp    al, 0
  3861.                 je    WriteData
  3862.                 mov    al, 'a'
  3863.                 ComWrite
  3864.  
  3865. Description:
  3866.  
  3867. ComTstIn polls the port to see if the transmitter is currently busy.  If so,
  3868. it returns a zero in AL, else it returns a one.
  3869.  
  3870. Warning: do *not* use this routine while operating in the interrupt mode.
  3871. This routine is for polled I/O only.
  3872.  
  3873. Include:    ser.a or stdlib.a
  3874.  
  3875. Routine:  ComGetLSR
  3876. -------------------
  3877.  
  3878. Author:                  Randall Hyde
  3879.  
  3880. Category:                 Serial Communications
  3881.  
  3882. Registers on entry:       None
  3883.  
  3884. Registers on return:      AL = LSR value
  3885.  
  3886. Flags affected:           None
  3887.  
  3888. Example of Usage:
  3889.  
  3890.             ComGetLSR
  3891.             <do something with value in LSR>
  3892. Description:
  3893.  
  3894. Reads the LSR (line status register) and returns this value in AL.  The
  3895. LSR using the following layout.
  3896.  
  3897.  Line Status Register (LSR):
  3898.  
  3899.  bit 0-    Data Ready
  3900.  bit 1-    Overrun error
  3901.  bit 2-    Parity error
  3902.  bit 3-    Framing error
  3903.  bit 4-    Break Interrupt
  3904.  bit 5-    Transmitter holding register is empty.
  3905.  bit 6-    Transmit shift register is empty.
  3906.  bit 7-    Always zero.
  3907.  
  3908. Warning: In general, it is not a good idea to call this routine while
  3909. the interrupt system is active.  It won't hurt anything, but the value
  3910. you get back may not reflect properly upon the last/next character you
  3911. read.
  3912.  
  3913. Include:    ser.a or stdlib.a
  3914.  
  3915. Routine:  ComGetMSR
  3916. -------------------
  3917.  
  3918. Author:                  Randall Hyde
  3919.  
  3920. Category:                 Serial Communications
  3921.  
  3922. Registers on entry:       None
  3923.  
  3924. Registers on return:      AL = MSR value
  3925.  
  3926. Flags affected:           None
  3927.  
  3928. Example of Usage:
  3929.  
  3930.             ComGetMSR
  3931.             <do something with value in MSR>
  3932. Description:
  3933.  
  3934. The MSR (modem status register) bits are defined as follows:
  3935.  
  3936.  Modem Status Register (MSR):
  3937.  
  3938.  bit 0-    Delta CTS
  3939.  bit 1-    Delta DSR
  3940.  bit 2-    Trailing edge ring indicator
  3941.  bit 3-    Delta carrier detect
  3942.  bit 4-    Clear to send
  3943.  bit 5-    Data Set Ready
  3944.  bit 6-    Ring indicator
  3945.  bit 7-    Data carrier detect
  3946.  
  3947.  
  3948. Warning: In general, it is not a good idea to call this routine while
  3949. the interrupt system is active.  It won't hurt anything, but the value
  3950. you get back may not reflect properly upon the last/next character you
  3951. read.
  3952.  
  3953. Include:    ser.a or stdlib.a
  3954.  
  3955. Routine:  ComGetMCR
  3956. -------------------
  3957.  
  3958. Author:                  Randall Hyde
  3959.  
  3960. Category:                 Serial Communications
  3961.  
  3962. Registers on entry:       None
  3963.  
  3964. Registers on return:      AL = MCR value
  3965.  
  3966. Flags affected:           None
  3967.  
  3968. Example of Usage:
  3969.  
  3970.             ComGetMCR
  3971.             <do something with value in MCR>
  3972. Description:
  3973.  
  3974. The MCR (modem control register) bits are defined as follows:
  3975.  
  3976.  Modem Control Register (MCR):
  3977.  
  3978.  bit 0-        Data Terminal Ready (DTR)
  3979.  bit 1-        Request to send (RTS)
  3980.  bit 2-        OUT 1
  3981.  bit 3-        OUT 2
  3982.  bit 4-        Loop back control.
  3983.  bits 5-7-    Always zero.
  3984.  
  3985.  
  3986. The DTR and RTS bits control the function of these lines on the 8250.
  3987. They are useful mainly for polled I/O handshake operations (though they
  3988. *could* be used with interrupt I/O, it's rarely necessary unless your
  3989. main application is *really* slow and the data is coming in real fast.
  3990.  
  3991. Out1 and Out2 control output pins on the 8255.  Keep in mind that the OUT1
  3992. pin enables/disables the serial port interrupts.  Play with this *only* if
  3993. you want to control the interrupt enable.
  3994.  
  3995. Loop back control is mainly useful for testing the serial port or checking
  3996. to see if a serial chip is present.
  3997.  
  3998. Include:    ser.a or stdlib.a
  3999.  
  4000. Routine:  ComSetMCR
  4001. -------------------
  4002.  
  4003. Author:                  Randall Hyde
  4004.  
  4005. Category:                 Serial Communications
  4006.  
  4007. Registers on entry:       AL = new MCR value
  4008.  
  4009. Registers on return:      None
  4010.  
  4011. Flags affected:           None
  4012.  
  4013. Example of Usage:
  4014.  
  4015.             mov    al, NewMCRValue
  4016.             ComSetMCR
  4017.  
  4018. Description:
  4019.  
  4020. This routine writes the value in AL to the modem control register.  See
  4021. ComGetMCR for details on the MCR register.
  4022.  
  4023. Include:    ser.a or stdlib.a
  4024.  
  4025. Routine:  ComGetLCR
  4026. -------------------
  4027.  
  4028. Author:                  Randall Hyde
  4029.  
  4030. Category:                 Serial Communications
  4031.  
  4032. Registers on entry:       None
  4033.  
  4034. Registers on return:      AL = LCR value
  4035.  
  4036. Flags affected:           None
  4037.  
  4038. Example of Usage:
  4039.  
  4040.             ComGetLCR
  4041.             <do something with value in LCR>
  4042. Description:
  4043.  
  4044. The LCR (line control register) bits are defined as follows:
  4045.  
  4046.  Line Control Register (LCR):
  4047.  
  4048.  bits 0,1-    Word length (00=5, 01=6, 10=7, 11=8 bits).
  4049.  bit 2-        Stop bits (0=1, 1=2 stop bits [1-1/2 if 5 data bits]).
  4050.  bit 3-        Parity enabled if one.
  4051.  bit 4-        0 for odd parity, 1 for even parity (assuming bit 3 = 1).
  4052.  bit 5-        1 for stuck parity.
  4053.  bit 6-        1=force break.
  4054.  bit 7-        1=Divisor latch access bit.  0=rcv/xmit access bit.
  4055.  
  4056. Since the standard library provides routines to initialize the serial chip
  4057. (which is the purpose of this port) you shouldn't really mess with this
  4058. port at all.  You may, however, use ComGetLCR to see what the current
  4059. settings are before making any changes.
  4060.  
  4061. Warning: (applies mainly to ComSetLCR) DO NOT, UNDER ANY CIRCUMSTANCES,
  4062. CHANGE THE DIVISOR LATCH ACCESS BIT WHILE OPERATING IN INTERRUPT MODE.
  4063. The interrupt service routine assumes the rcv/xmit register is mapped in
  4064. whenever an interrupt occurs.  If you must play with the divisor latch,
  4065. turn off interrupts before changing it.  Always set the divisor latch
  4066. access bit back to zero before turning interrupts back on.
  4067.  
  4068. Include:    ser.a or stdlib.a
  4069.  
  4070. Routine:  ComSetLCR
  4071. -------------------
  4072.  
  4073. Author:                  Randall Hyde
  4074.  
  4075. Category:                 Serial Communications
  4076.  
  4077. Registers on entry:       AL = new LCR value
  4078.  
  4079. Registers on return:      None
  4080.  
  4081. Flags affected:           None
  4082.  
  4083. Example of Usage:
  4084.  
  4085. ; If this maps in the divisor latch, be sure we're not operating with
  4086. ; serial interrupts!
  4087.  
  4088.             mov    al, NewLCRValue
  4089.             ComSetLCR
  4090.  
  4091. Description:
  4092.  
  4093. This routine writes the value in AL to the line control register.  See
  4094. ComGetLCR for details on the LCR register.  Especially note the warning
  4095. about the divisor latch access bit.
  4096.  
  4097. Include:    ser.a or stdlib.a
  4098.  
  4099. Routine:  ComGetIIR
  4100. -------------------
  4101.  
  4102. Author:                  Randall Hyde
  4103.  
  4104. Category:                 Serial Communications
  4105.  
  4106. Registers on entry:       None
  4107.  
  4108. Registers on return:      AL = IIR value
  4109.  
  4110. Flags affected:           None
  4111.  
  4112. Example of Usage:
  4113.  
  4114.             ComGetIIR
  4115.             <do something with value in IIR>
  4116. Description:
  4117.  
  4118. The IIR (interrupt identification register) bits are defined as follows:
  4119.  
  4120.  Interrupt ID Register (IIR):
  4121.  
  4122.  bit 0-        No interrupt is pending (interrupt pending if zero).
  4123.  bits 1,2-    Binary value denoting source of interrupt:
  4124.             00-Modem status
  4125.             01-Transmitter Hold Register Empty
  4126.             10-Received Data Available
  4127.             11-Receiver line status
  4128.  bits 3-7    Always zero.
  4129.  
  4130. This value is of little use to anyone except the interrupt service routine.
  4131. The ISR is the only code which should really access this port.
  4132.  
  4133. Include:    ser.a or stdlib.a
  4134.  
  4135. Routine:  ComGetIER
  4136. -------------------
  4137.  
  4138. Author:                  Randall Hyde
  4139.  
  4140. Category:                 Serial Communications
  4141.  
  4142. Registers on entry:       None
  4143.  
  4144. Registers on return:      AL = IER value
  4145.  
  4146. Flags affected:           None
  4147.  
  4148. Example of Usage:
  4149.  
  4150.             ComGetIER
  4151.             <do something with value in IER>
  4152. Description:
  4153.  
  4154. The IER (line control register) bits are defined as follows:
  4155.  
  4156.  Interupt enable register (IER):
  4157.  
  4158.         If one:
  4159.  bit 0-        Enables received data available interrupt.
  4160.  bit 1-        Enables transmitter holding register empty interrupt.
  4161.  bit 2-        Enables receiver line status interrupt.
  4162.  bit 3-        Enables the modem status interrupt.
  4163.  bits 4-7-    Always set to zero.
  4164.  
  4165. Normally, the interrupt initialization procedure sets up this port.  You may
  4166. read or change its value as you deem necessary to control the types of
  4167. interrupts the system generates.  Note that the interrupt service routine
  4168. (ISR) in the library ignores errors.  You will need to modify the ISR if you
  4169. need to trap errors.
  4170.  
  4171. Include:    ser.a or stdlib.a
  4172.  
  4173. Routine:  ComSetIER
  4174. -------------------
  4175.  
  4176. Author:                  Randall Hyde
  4177.  
  4178. Category:                 Serial Communications
  4179.  
  4180. Registers on entry:       AL = new IER value
  4181.  
  4182. Registers on return:      None
  4183.  
  4184. Flags affected:           None
  4185.  
  4186. Example of Usage:
  4187.  
  4188.             mov    al, NewIERValue
  4189.             ComSetIER
  4190.  
  4191. Description:
  4192.  
  4193. Writes the value in AL to the IER.  See ComGetIER for more details.
  4194.  
  4195. Include:    ser.a or stdlib.a
  4196.  
  4197. Routine:  ComInitIntr
  4198. ---------------------
  4199.  
  4200. Author:                  Randall Hyde
  4201.  
  4202. Category:                 Serial Communications
  4203.  
  4204. Registers on entry:       None
  4205.  
  4206. Registers on return:      None
  4207.  
  4208. Flags affected:           None
  4209.  
  4210. Example of Usage:
  4211.  
  4212.             ComInitIntr
  4213.  
  4214. Description:
  4215.  
  4216. Sets up the chip to generate interrupts and programs the PC to transfer
  4217. control to the library serial interrupt service routine when an interrupt
  4218. occurs.  Note that other than interrupt initialization, this code does not
  4219. initialize the 8250 chip.
  4220.  
  4221. Include:    ser.a or stdlib.a
  4222.  
  4223. Routine:  ComDisIntr
  4224. --------------------
  4225.  
  4226. Author:                  Randall Hyde
  4227.  
  4228. Category:                 Serial Communications
  4229.  
  4230. Registers on entry:       None
  4231.  
  4232. Registers on return:      None
  4233.  
  4234. Flags affected:           None
  4235.  
  4236. Example of Usage:
  4237.  
  4238.             ComDisIntr
  4239.  
  4240. Description:
  4241.  
  4242. This routine uninstalls the ISR and programs the chip to stop the generation
  4243. of interrupts.  You must call ComInitIntr after calling this routine to
  4244. turn the interrupt system back on.
  4245.  
  4246. Include:    ser.a or stdlib.a
  4247.  
  4248. Routine:  ComIn
  4249. ---------------
  4250.  
  4251. Author:                  Randall Hyde
  4252.  
  4253. Category:                 Serial Communications
  4254.  
  4255. Registers on entry:       None
  4256.  
  4257. Registers on return:      AL=character read from buffer or port
  4258.  
  4259. Flags affected:           None
  4260.  
  4261. Example of Usage:
  4262.  
  4263.             ComIn
  4264.             <Do something with AL>
  4265.  
  4266. Description:
  4267.  
  4268. ComIn is the input routine associated with interrupt I/O.  It reads the
  4269. next available character from the serial input buffer.  If no characters
  4270. are avialable in the buffer, it waits until the system receives one before
  4271. returning.
  4272.  
  4273. Include:    ser.a or stdlib.a
  4274.  
  4275. Routine:  ComOut
  4276. ----------------
  4277.  
  4278. Author:                  Randall Hyde
  4279.  
  4280. Category:                 Serial Communications
  4281.  
  4282. Registers on entry:       AL=Character to output
  4283.  
  4284. Registers on return:      None
  4285.  
  4286. Flags affected:           None
  4287.  
  4288. Example of Usage:
  4289.  
  4290.             <Get character to write into AL>
  4291.             ComOut
  4292.  
  4293. Description:
  4294.  
  4295. ComOut is the output routine associated with interrupt I/O.  If the serial
  4296. transmitter isn't currently busy, it will immediately write the data to the
  4297. serial port.  If it is busy, it will buffer the character up.  In most cases
  4298. this routine returns quickly to its caller.  The only time this routine
  4299. will delay is if the buffer is full can you cannot add any additional
  4300. characters to it.
  4301.  
  4302. Include:    ser.a or stdlib.a
  4303.  
  4304. CHARSETS
  4305.  
  4306. Createsets    Creates a set on the heap
  4307. Emptyset    Cleans out set
  4308. Rangeset    Add a range of values to a set
  4309. Addstr        Add a group of characters to a set
  4310. Rmvstr        Remove a string from a set
  4311. AddChar        Add a single character to a set
  4312. Rmvchar        Remove a single character to a set
  4313. Member        Find if a character is in a set
  4314. CopySet        Makes a verbatim copy of a set to another
  4315. SetUnion    Computes the union of two sets
  4316. SetIntersect    Computes the intersection of two sets into a third
  4317. SetDifference    Removes items in second set which are in first
  4318. Nextitem        Searches the first character (item) in the set
  4319.                 pointing to its mask byte
  4320. Rmvitem        Removes an item from a set
  4321.  
  4322.  
  4323.  
  4324. UTIL
  4325.  
  4326. ISize           Calculate number of spaces needed to print signed integer
  4327. USize           Calculate number of spaces needed to print unsigned integer
  4328. LSize           Calculate number of spaces needed to print signed long integer
  4329. ULSize          Calculate number of spaces needed to print unsigned long integer
  4330. IsAlNum        Checks to see if AL is in the range of A-Z, a-z, 0-9
  4331. IsXDigit    Checks to see if AL is in the range of A-F, a-f, 0-9
  4332. IsDigit        Checks to see if AL is in the range of 0-9
  4333. IsAlpha        Checks to see if AL is in the range of A-Z, a-z
  4334. IsLower        Checks to see if AL is in the range of a-z
  4335. IsUpper        Checks to see if AL is in the range of A-Z
  4336.  
  4337.  
  4338.  
  4339. STRINGS
  4340.  
  4341. The following string routines take as many as four different forms: strxxx,
  4342. strxxxl, strxxxm, and strxxxlm.  These routines differ in how they store
  4343. the destination string into memory and where they obtain their source strings.
  4344.  
  4345. Routines of the form strxxx generally expect a single source string address
  4346. in ES:DI or a source and destination string in ES:DI & DX:SI.  If these
  4347. routines produce a string, they generally store the result into the buffer
  4348. pointed at by ES:DI upon entry.  They return with ES:DI pointing at the
  4349. first character of the destination string.
  4350.  
  4351. Routines of the form strxxxl have a "literal source string".  A literal
  4352. source string follows the call to the routine in the code stream.  E.g.,
  4353.  
  4354.             strcatl
  4355.             db    "Add this string to ES:DI",0
  4356.  
  4357. Routines of the form strxxxm automatically allocate storage for a source
  4358. string on the heap and return a pointer to this string in ES:DI.
  4359.  
  4360. Routines of the form strxxxlm have a literal source string in the code
  4361. stream and allocate storage for the destination string on the heap.
  4362.  
  4363.  
  4364.  
  4365. Strcpy        Copies string. 
  4366. Strcpyl        Copies string literal
  4367. StrDup        Copies string to newly allocated memory
  4368. StrDupl        Copies string to newly allocated memory from literal
  4369. Strlen        Calculate length of string
  4370. Strcat        Concatenate two strings
  4371. Strcatm        Concatenate two strings, allocating enough memory for the final
  4372.         resulting string on the heap
  4373. Strcatl        Concatenate string from literal
  4374. Strcatml    Concatenate string from literal to allocated memory
  4375. Strchr        Searches for first occurence of a character in a string
  4376. Strstr        Searches for the position of a substring within another string
  4377. Strcmp        Compares one string to another
  4378. Strcmpl        Compares one string to literal string
  4379. Stricmp        Compares one string to another disregarding case
  4380. Strupr        Converts a string to uppercase
  4381. Struprm        Copies string to heap, then converts to upper and returns address
  4382. Strlwr        Convert string to lower case
  4383. Strlwrm        Copies string to heap, converts, then returns new string
  4384. Strset        Overwrites data on input string with character in AL
  4385. Strsetm        Allocates new strings, then overwrites with character in AL
  4386. Strspan        Compares strings, returning 1st position not equal
  4387. Strspanl    Compares strings, returning 1st position not equal, literal
  4388. Strcspan    Compares strings, returning 1st position that _IS_ equal
  4389. Strcplanl    Compares strings, returning 1st position that _IS_ equal,literal
  4390. StrIns        Inserts one string into another
  4391. StrInsl        Inserts one string into another, literal
  4392. StrInsm        Inserts one string into another after allocating memory
  4393. StrInsml    Inserts one string into another after allocating memory, literal
  4394. StrDel        Deletes characters from a string
  4395. StrDelm        Deletes characters from a copy of a string
  4396. StrTrim        Removes trailing spaces from a string
  4397. StrTrimm    Removes trailing spaces from a copy of a string
  4398. StrBlkDel    Removes leading spaces from a string
  4399. StrBlkDelm    Removes leading spaces from a copy of a string
  4400. Strrev        Reverses the characters in a string. ie: "BLAH" -> "HALB"
  4401. Strrevm        Reverses the characters in a copy of a string
  4402. StrBDel        Removes leading spaces from a string
  4403. StrBDelm    Removes leading spaces from a copy of a string
  4404. ToHex        Converts a stream of binary vaues into Intel Hex format
  4405.  
  4406.  
  4407. STDOUT
  4408.  
  4409. Putc        Print a character out to stdout
  4410. PutCR        Print a CR/LF to stdout
  4411. PucStdOut    Print a character to stdout
  4412. PutcBIOS    Use BIOS to print a character to the _SCREEN_
  4413. GetOuAdrs    Get the address of the current output routine
  4414. SetOutAdrs    Redirects calls to output routine to user defined
  4415. PushOutAdrs    Pushes current output address to internal stack
  4416. PopOutAdrs    Pops output address from internal stack and sets
  4417. Puts        Print a string to stdout
  4418. Puth        Print a value out in hex format
  4419. Putw        Print a value out in word hex format
  4420. Puti        Print a value out in signed integer format
  4421. Putu        Print a value out in unsigned integer format
  4422. Putl        Print a value out in signed long integer format
  4423. Putul        Print a value out in unsigned long integer format
  4424. PutISize    Print a value out in signed integer format using minimum spaces
  4425. PutUSize    Print a value out in unsigned integer format using minimum spaces
  4426. PutLSize    Print a value out in signed long format using minimum spaces
  4427. PutULSize    Print a value out in unsigned long fomat using minimum spaces
  4428. Print        Print out a literal string
  4429. Printf        Print out a literal string using C library type formatters
  4430. Printff        Print out a literal string using C library type formatters. Also
  4431.         supports printout out floating point values
  4432.  
  4433.  
  4434. STDIN
  4435.  
  4436. Getc        Gets a character from STDIN
  4437. GetcStdIn    Gets a character from STDIN
  4438. GetcBIOS    Gets a character using BIOS. Redirection is not allowed
  4439. SetInAdrs    Sets the address to the routine which you want to use for input
  4440. GetInAdrs    Gets the address which is being used to take input
  4441. PushInAdrs    Pushes the address of the input routine to an internal stack
  4442. PopInAdrs    Pop the address of the input routine from an internal stack
  4443. Gets        Get a string from STDIN
  4444. Getsm        Get a string in STDIN and stuff into newly alloacted buffer
  4445. Scanf        Gets string from STDIN using C library type formatters
  4446.  
  4447.  
  4448. SERIAL PORT STUFF
  4449.  
  4450. ComBaud        Inits the seral port to a user defined speed
  4451. ComStop        Inits number of stop bits to use in transmission
  4452. ComSize        Inits number of data bits to use in transmission
  4453. ComParity    Inits the serial port as to whether or not to use parity checking
  4454. ComRead        Reads character from serial port
  4455. ComWrite    Transmits character to serial port
  4456. ComTstIn    Checks to see if character is availble in buffer. Does not read.
  4457. ComTstOut    Checks if character can be transmitted
  4458. ComGetLSR    Reads current status of Line Status Register
  4459. ComGetMSR    Reads current status of Modem Status Regster
  4460. ComGetMCR    Reads current status of Modem Control Register
  4461. ComGetLCR    Reads current status of Line Control Regiter
  4462. ComGetIIR    Reads current status of Interrupt Identification Register
  4463. ComGetIER    Reads current status of Interupt Enable Register
  4464. ComSetMCR    Writes value to Modem Control Register
  4465. ComSetLCR    Writes value to Line Control Register
  4466. ComSetIER    Writes value to Interrupt Enable Register
  4467. ComInitIntr    Sets up interrupts and progams to control serial chip
  4468. ComDisIntr    Untinstalls all programs installed with ComInitIntr
  4469. ComIn        Reads chracter from serial port. Will wait if none available.
  4470. ComOut        Writes character to serial port, waiting if port is busy.
  4471.  
  4472.  
  4473. PROCESS
  4474.  
  4475. Prcsinit    Starts the process manager
  4476. Prcsquit    Shutsdown the process manager
  4477. Fork        Spawns a new process
  4478. Die        Kills the current process
  4479. Kill        Lets one process terminate another
  4480. Yield        Forces context switch, surrendering rest of current time slice
  4481. CoInit        Inits the CoRoutine package
  4482. CoCall        Switches context between two coroutines
  4483. CoCalll        Switches context between two coroutines, passing info another way
  4484. WaitSemaph    Protects critical regions in memory
  4485. RlsSemaPh    Releases a semaphore that the current process has aquired
  4486.  
  4487.  
  4488. PATTERN
  4489.  
  4490.  
  4491. Spancset    Match any number of characters belonging to a character set
  4492. Brkcset        Match any number of characters which are *not* in a character set
  4493. MatchStr    Matches a specified string
  4494. MatchToStr    Match characters in string until specified substring
  4495. MatchChar    Matches a single character
  4496. MatchChars    Matches zero or more occurrences of the same character
  4497. MatchToChar    Matches characters up to and including specified character
  4498. MatchToPat    Matches all characters up to specified characters
  4499. Anycset        Matches single character from a character set
  4500. NotAnycset    Match single character which is not in character set
  4501. EOS        Matches end of string
  4502. ARB        Matches arbitary number of characters
  4503. ARBNUM        Matches arbitary number of strings
  4504. Skip        Matches "n" arbitary characters. 
  4505. POS        Matches at position "n" in the string
  4506. RPOS        Matches at position "n" from the end of the string
  4507. GOTOpos        Moves to position in string
  4508. RGOTOpos    Moves to position "n" from end of string
  4509.  
  4510.  
  4511. MISC
  4512.  
  4513. Random        Generate a random number
  4514. Randomize    Reseed random number generator based on time of day
  4515. cpuid        Identifies CPU
  4516. Argc        Return number of command line parameters
  4517. Argv        Returns address to string of command line parameter specified
  4518. GetEnv        Returns address of environment table information
  4519. DOS        Invokes DOS INT 21h interrupt
  4520. ExitPgm        Exits current program and returns to DOS
  4521.  
  4522.  
  4523.  
  4524. MEMORY
  4525.  
  4526. MemInit        Initializes memory manager. Must be called first.
  4527. MemInit2    Initializes another part of memory manager
  4528. Malloc        Dynamically allocate memory
  4529. Realloc        Resize a block of memory already allocated with Malloc
  4530. Free        Deallocate a chunk of memory allocated with Malloc
  4531. DupPtr        Replicate a pointer to a chunk of memory so free won't deallocate
  4532.         it until all the pointers are taken care of
  4533. IsInHeap    Tells you if ES:DI points somewhere in the heap
  4534. IsPtr        Tells you if ES:DI points to a properlly allocated chunk of heap
  4535. BlockSize    Returns size of block currently pointed to in the heap
  4536. MemAvail    Returns size of largest free block on the heap
  4537. MemFree        Returns size of total bytes free on the heap
  4538.  
  4539.  
  4540.  
  4541. LIST
  4542.  
  4543. CreateList    Allocates storage for a list variable on the head
  4544. AppendLast    Add a node to the list
  4545. Remove1st    Removes the first item from a list
  4546. Peek1st        Looks at the first item from a list
  4547. Insert1st    Inserts a node at the first node from a list
  4548. RemoveLast    Removes the last node from a list
  4549. PeekLast    Looks at the last item from a list
  4550. InsertCur    Inserts a node into the list
  4551. InsertmCur    Builds a node on the heap, then inserts that into the list
  4552. AppendCur    Inserts a node into the list after the current node pointed to
  4553. AppendmCur    Builds node on heap, then inserts that after current node
  4554. RemoveCur    Removes current node from the list
  4555. Peek        Looks at current node on the list
  4556. SetCur        Sets the specified node as the current node
  4557. Insert        Inserts a new node before a specified node in the list
  4558. Append        Inserts a new node after a specified node in the list
  4559. Remove        Removes the specified node from the list
  4560.  
  4561.  
  4562.  
  4563.  
  4564. FLOATING POINT (FP)
  4565.  
  4566. lsfpa        Load single percision float value into internal accumulator
  4567. ssfpa        Store single percision float value from accumulator to memory
  4568. ldfpa        Load double percision float value into internal accumulator
  4569. sdfpa        Store double percision float value from accumulator to memory
  4570. lefpa        Load extended percision float value into internal accumulator
  4571. lefpal        lefpa with a literal value after it in the code
  4572. sefpa        Store extended percision float value from accumulator to memory
  4573. lsfpo        lsfpa a value, then convert to extended percision
  4574. ldfpo        ldfpa a value, then convert to extended percision
  4575. lefpo        lefpa a value, then convert to extended percision
  4576. lefpol        lefpo a value, with the value being literal in the code
  4577. itof        Convert a 16bit signed integer to float
  4578. utof        Convert a 16bit unsigned integer to float
  4579. ultof        Convert a 32bit unsigned integer to float
  4580. ltof        Convert a 32bit signed integer to float
  4581. ftoi        Convert float number to signed 16bit integer format
  4582. ftou        Convert float number to unsigned 16bit integer format
  4583. ftol        Convert float number to signed 32bit integer format
  4584. ftoul        Convert float number to unsigned 32bit integer format
  4585. fpadd        Add float accumulator to float operand
  4586. fpsub        Subtract float operand from the float accumulator
  4587. fpsmp        Compare float accumulator to operand and set flags accordingly
  4588. fpmul        Multiply float operand to float accumulator
  4589. fpdiv        Divides float accumulator by operand
  4590. ftoa        Converts float number into string, preserving DI
  4591. ftoa2        Converts float number into string, not preserving DI
  4592. ftoam        Converts float to string, allocating enough space for string
  4593. etoa        Convert float to string using scientific notation
  4594. etoa2        Works like etoa, except not preserving DI
  4595. etoam        Works like etoa, this time allocing space on the heap for string
  4596. atof        Converts string into float
  4597.  
  4598.  
  4599.  
  4600. DATE TIME
  4601.  
  4602. Date        Converts DOS system date into string ( mm/dd/yy )
  4603. Date2        Converts DOS system date into string, not preserving DI
  4604. Datem        Converts DOS system date into string allocated from heap
  4605. xDate        Converts current DOS system date into string
  4606. xDate2        Converts current DOS system date into string, killing DI
  4607. xDatem        Converts current DOS system date to string with memory from heap
  4608. lDate        Converts DOS date into string ( mmm, dd, yyyy )
  4609. lDate2        Converts DOS date into string killing DI
  4610. lDatem        Converts DOS date into string, memory allocated from heap
  4611. xlDate        Converts current DOS date into string
  4612. xlDate2        Converts current DOS date into string killing DI
  4613. xlDatem        Converts current DOS date into string allocated from heap
  4614. atod        Converts string (mm/dd/yy or mm-dd-yy) into DOS date
  4615. atod2        Converts string into DOS date, killing DI
  4616. atot        Converts string (hh:mm:ss or hh:mm:ss.xxx) into DOS time
  4617. atot2        Converts string into DOS time killing DI
  4618. time        Converts DOS time to string
  4619. time2        Converts DOS time to string, killing DI
  4620. timem        Converts DOS time to string, allocated from heap
  4621. xtime        Converts current DOS time to string
  4622. xtime2        Converts current DOS time to string, killing DI
  4623. xtimem        Converts current DOS time to string, allocated from heap
  4624.  
  4625.  
  4626. CONVERSION
  4627.  
  4628. atol        Converts string of numbers to signed 32bit integer
  4629. atoul        Converts string of numbers to unsigned 32bit integer
  4630. atou        Converts string of numbers to unsigned 16bit integer
  4631. atoh        Converts string of hex numbers to unsigned 16bit integer
  4632. atoh2        Converts string of hex numbers to unsigned 16bit int killing DI
  4633. atolh        Converts string of hex numbers to unsigned 32bit int
  4634. atolh2        Converts string of hex numbers to unsigned 32bit int killing DI
  4635. atoi        Converts string of numbers to signed 16bit integer
  4636. itoa        Converts signed integer to string
  4637. itoam        Converts signed integer to string, allocting space from heap
  4638. itoa2        Converts signed integer to string, killing DI
  4639. utoa        Converts unsigned integer to string
  4640. utoam        Converts unsigned integer to string, allocating space from heap
  4641. utoa2        Converts unsigned integer to string, killing DI
  4642. htoa        Converts 8bit hex value to string
  4643. htoa2        Converts 8bit hex value to string, killing DI
  4644. htoam        Converts 8bit hex value to string, allocating space from heap
  4645. wtoa        Converts 16bit hex value to string
  4646. wtoa2        Converts 16bit hex value to string, killing DI
  4647. wtoam        Converts 16bit hex value to string, allocating space from heap
  4648. ltoa        Converts 32bit signed integer to string
  4649. ltoa2        Converts 32bit signed integer to string, killing DI
  4650. ltoam        Converts 32bit signed integer to string, getting space from heap
  4651. ultoa        Converts 32bit unsigned int to string
  4652. ultoa2        Converts 32bit unsigned int to string, killing DI
  4653. ultoam        Converts 32bit unsigned int to string, getting space from heap
  4654. sprintf        In memory print formatting
  4655. sprintf2    In memory print formatting, killing DI
  4656. sprintfm    In memory print formatting, getting space from heap
  4657. sscanf        In memory input formatting
  4658. sscanf2        In memory input formatting, killing DI
  4659. sscanfm        In memory input formatting, getting space from heap
  4660. tolower        Converts character to lowercase
  4661. toupper        Converts character to uppercase
  4662.          
  4663.  
  4664.     
  4665. By: Steve Shah
  4666.     sshah@ucrengr.ucr.edu
  4667.     sshah@watserv.ucr.edu
  4668.     sshah@mozart.ucr.edu
  4669.     
  4670.         Pick one -- any one.......
  4671. Current version:
  4672.     UCRASM 31
  4673.     Compiled 1.0 -- June 7, 1993  10:40a
  4674.  
  4675.  
  4676.  
  4677. Standard Input Routines:
  4678. Character Input Routines
  4679. ------------------------
  4680.  
  4681.  
  4682.     The character input routines take input from either a standard
  4683. device (keyboard, etc.) or a standard library.  After the character input
  4684. routines receive the characters they either place the characters on the stack
  4685. and/or return.  The character input routines work similar to the "C" character
  4686. input routines.
  4687.  
  4688.  
  4689.  
  4690. Routine:  Getc
  4691. --------------
  4692.  
  4693.  
  4694. Category:             Character Input Routine
  4695.  
  4696.  
  4697. Registers on Entry:   None
  4698.  
  4699.  
  4700. Registers on Return:  AL- Character from input device.
  4701.                       AH- 0 if eof, 1 if not eof.
  4702.  
  4703.  
  4704. Flags Affected:       Carry- 0 if no error, 1 if error.  If error occurs, AX
  4705.                              contains DOS error code.
  4706.  
  4707.  
  4708. Example of Usage:  
  4709.                       getc
  4710.                       mov     KbdChar, al
  4711.                       putc
  4712.  
  4713.  
  4714. Description:  This routine reads a character from the standard input device.
  4715.               This call is synchronous, that is, it does not return until a
  4716.               character is available.  The Default input device is DOS
  4717.               standard input.
  4718.  
  4719.               Getc returns two types of values: extended ASCII (codes 1-255)
  4720.               and IBM keyboard scan codes.  If Getc returns a non-zero value,
  4721.               you may interpret this value as an ASCII character.  If Getc
  4722.               returns zero, you must call Getc again to get the actual
  4723.               keypress.
  4724.  
  4725.               The second call returns an IBM PC keyboard scan code.
  4726.  
  4727.               Since the user may redirect input from the DOS command line,
  4728.               there is the possibility of encountering end-of-file (eof)
  4729.               when calling getc.  Getc uses the AH register to return eof
  4730.               status.  AH contains the number of characters actually read
  4731.               from the standard input device.  If it returns one, then
  4732.               you've got a valid character.  If it returns zero, you've
  4733.               reached end of file.  Note that pressing control-z forces an
  4734.               end of file condition when reading data from the keyboard.
  4735.  
  4736.               This routine returns the carry flag clear if the operation
  4737.               was successful.  It returns the carry flag set if some sort
  4738.           of error occurred while reading the character.  Note that eof
  4739.               is not an error condition.  Upon reaching the end of file,
  4740.               Getc returns with the carry flag clear.  If getc is seen from
  4741.               a file the control-z is not seen as an end-of-file marker,
  4742.               but just read in as a character of the file.
  4743.  
  4744.               Control-c if read from a keyboard device aborts the program.
  4745.               However if when reading something other than a keyboard
  4746.           (files, serial ports), control-c from the input source
  4747.               returns control-c.  However when pressing control-break
  4748.               the program will abort regardless of the input source.
  4749.  
  4750.               Regarding CR/LF, if the input is from a device, (eg. keyboard
  4751.               serial port) getc returns whatever that device driver returns,
  4752.               (generally CR without a LF).  However if the input is from
  4753.               a file, getc stripes a single LF if it immediately follows
  4754.               the CR.
  4755.  
  4756.               When using getc files operate in "cooked" mode.  While
  4757.               devices operate in "pseudo-cooked" mode, which means no
  4758.           buffering, no CR -> CR/LF, but it handles control-c, and
  4759.               control-z.
  4760.  
  4761.           See the sources for more information about GETC's internal
  4762.           operation.
  4763.  
  4764. Include:    stdlib.a or stdin.a
  4765.  
  4766.  
  4767.  
  4768.  
  4769. Routine:   GetcStdIn
  4770. --------------------
  4771.  
  4772.  
  4773. Category:             Character Input Routine
  4774.  
  4775. Register on entry:    None.
  4776.  
  4777. Register on return:   AL- Character from input device.
  4778.  
  4779. Flags affected:       AH- 0 if eof, 1 if not eof.
  4780.                       Carry- 0 if no error, 1 if error
  4781.                       (AX contains DOS error code if error occurs).
  4782.  
  4783.  
  4784. Example of Usage:
  4785.                       GetcStdIn
  4786.                       mov     InputChr, al
  4787.                       putc
  4788.  
  4789.  
  4790. Description:    This routine reads a character from the DOS standard input
  4791.                 device.  This call is synchronous, that is, it does not return
  4792.                 until a character is available.  See the description of Getc
  4793.                 above for more details.
  4794.  
  4795.         The difference between Getc and GetcStdIn is that your
  4796.         program can redirect Getc using other calls in this library.
  4797.         GetcStdIn calls DOS directly without going through this
  4798.         redirection mechanism.
  4799.  
  4800.  
  4801. Include:        stdlib.a or stdin.a
  4802.  
  4803.  
  4804.  
  4805.  
  4806.  
  4807.  
  4808. Routine:   GetcBIOS
  4809. -------------------
  4810.  
  4811.  
  4812. Category:             Character Input Routine
  4813.  
  4814. Register on entry:    None
  4815.  
  4816. Register on return:   AL- Character from the keyboard.
  4817.  
  4818. Flags affected:       AH- 1 (always).  Carry- 0 (always).
  4819.  
  4820. Example of Usage:   
  4821.               GetcBIOS
  4822.                       mov     CharRead, al
  4823.                       putc
  4824.  
  4825.  
  4826. Description:   This routine reads a character from the keyboard.  This call is
  4827.                synchronous, that is it does not return until a character is
  4828.                available.
  4829.  
  4830.         Note that there is no special character processing.  This
  4831.         code does *not* check for EOF, control-C, or anything
  4832.         else like that.
  4833.  
  4834.  
  4835.  
  4836. Include:        stdlib.a or stdin.a
  4837.  
  4838.  
  4839.  
  4840. Routine:  SetInAdrs
  4841. -------------------
  4842.  
  4843. Category:               Character Input Routine
  4844.  
  4845. Registers on Entry:     ES:DI - address of new input routine
  4846.  
  4847. Registers on return:    None 
  4848.  
  4849. Flags affected:
  4850.  
  4851. Examples of Usage:
  4852.  
  4853.                         mov     es, seg NewInputRoutine
  4854.                         mov     di, offset NewInputRoutine
  4855.                         SetInAdrs
  4856.  
  4857.  
  4858.  
  4859.                         les     di, RoutinePtr
  4860.                         SetInAdrs
  4861.  
  4862.  
  4863. Description:    This routine redirects the stdlib standard input so that it 
  4864.                 calls the routine who's address you pass in es:di.  The
  4865.         routine (whose address appears in es:di) should be a "getc"
  4866.         routine which reads a character from somewhere and returns
  4867.         that character in AL.  It should also return EOF status in
  4868.         the AH register and error status in the carry flag (see
  4869.         the description of GETC for more details).
  4870.  
  4871.  
  4872. Include:                stdlib.a or stdin.a
  4873.  
  4874.  
  4875.  
  4876.  
  4877.  
  4878. Routine:   GetInAdrs
  4879. --------------------
  4880.  
  4881. Category:             Character Input Routine
  4882.  
  4883. Register on entry:    None
  4884.  
  4885. Register on return:   ES:DI - address of current input routine (called by Getc).
  4886.  
  4887. Flags affected:       None
  4888.  
  4889.  
  4890. Example of Usage:   
  4891.                       GetInAdrs
  4892.               mov     word ptr SaveInAdrs, di
  4893.               mov     word ptr SaveInAdrs+2, es
  4894.  
  4895.  
  4896. Description:   You can use this function to get the address of the current
  4897.            input routine, perhaps so you can save it or see if it is
  4898.            currently pointing at some particular piece of code.
  4899.            If you want to temporarily redirect the input and then restore
  4900.            the original input or outline, consider using
  4901.            PushInAdrs/PopInAdrs described later.
  4902.  
  4903.  
  4904. Include:        stdlib.a or stdin.a
  4905.  
  4906.  
  4907.  
  4908. Routine:   PushInAdrs
  4909. ---------------------
  4910.  
  4911. Category:             Character Input Routine
  4912.  
  4913. Register on entry:    ES:DI - Address of new input routine.
  4914.  
  4915. Register on return:   Carry=0 if operation successful.
  4916.                       Carry=1 if there were already 16 items on the stack.
  4917.                          
  4918. Example of Usage:
  4919.                       mov     es, seg NewInputRoutine
  4920.                       mov     di, offset NewInputRoutine
  4921.                       PushInAdrs
  4922.                         .
  4923.                         .
  4924.                         .
  4925.                       les     di, RoutinePtr
  4926.                       PushInAdrs
  4927.  
  4928.  
  4929. Description:   This routine "pushes" the current input address onto an
  4930.                internal stack and then copies the value in es:di into the
  4931.                current input routine pointer.  The PushInAdrs and PopInAdrs
  4932.                routines let you easily save and redirect the standard output
  4933.                and then restore the original output routine address later on.
  4934.                If you attempt to push more than 16 items on the stack,
  4935.                PushInAdrs will ignore your request and return with the
  4936.                carry flag set.  If PushInAdrs is successful, it will
  4937.                return with the carry flag clear.
  4938.  
  4939.  
  4940. Include:    stdlib.a or stdin.a
  4941.  
  4942.  
  4943.  
  4944.  
  4945.  
  4946. Routine:   PopInAdrs
  4947. --------------------
  4948.  
  4949. Category:             Character Input Routine
  4950.  
  4951. Register on entry:    None
  4952.  
  4953. Register on return:   ES:DI - Points at the previous stdout routine before
  4954.                       the pop.
  4955.  
  4956. Example of Usage:   
  4957.                       mov     es, seg NewInRoutine
  4958.               mov     di, offset NewInputRoutine
  4959.                       PushInAdrs
  4960.                         .
  4961.                         .
  4962.                         .
  4963.                       PopInAdrs
  4964.  
  4965.  
  4966. Description:   PopInAdrs undoes the effects of PushInAdrs.  It pops an item
  4967.                off the internal stack and stores it into the input routine
  4968.                pointer.  The previous value in the output pointer is returned
  4969.                in es:di.
  4970.  
  4971. Include:    stdlib.a or stdin.a
  4972.  
  4973.  
  4974.  
  4975.  
  4976.  
  4977. Routine:  Gets, Getsm
  4978. ---------------------
  4979.  
  4980. Category:             Character Input Routine
  4981.  
  4982. Register on entry:    ES:DI- Pointer to input buffer (gets only).
  4983.  
  4984. Register on return:   ES:DI - address of input of text.
  4985.                       carry-  0 if no error, 1 if error.
  4986.                       If error, AX contains: 0- End of
  4987.                       file encountered in middle of
  4988.                       string.  1- Memory allocation error (getsm only).
  4989.                       Other- DOS error code.
  4990.  
  4991.  
  4992. Flags affected:       None
  4993.  
  4994. Example of usage:    
  4995.                       getsm           ;Read a string from the
  4996.                                       ;keyboard
  4997.                       puts            ;Print it
  4998.               putcr           ;Print a new line
  4999.                       free            ;Deallocate storage for
  5000.                                       ;string.
  5001.  
  5002.               mov    di, seg buffer
  5003.               mov    es, di
  5004.               lea    di, buffer
  5005.               gets
  5006.               puts
  5007.               putcr
  5008.  
  5009.  
  5010. Description:       Reads a line of text from the stdlib standard input device.
  5011.         You must pass a pointer to the recipient buffer in es:di to
  5012.         the GETS routine.  GETSM automatically allocates storage for
  5013.         the string on the heap (up to 256 bytes) and returns a pointer
  5014.         to this block in es:di.
  5015.  
  5016.         Gets(m) returns all characters typed by the user except for the
  5017.         carriage return (ENTER) key code.  These routines return a
  5018.         zero-terminated string (with es:di pointing at the string).
  5019.         Exactly how Gets(m) treats the incoming data depends upon
  5020.         the source device, however, you can usually count on Gets(m)
  5021.         properly handling backspace (erases previous character),
  5022.         escape (erase entire line), and ENTER (accept current line).
  5023.  
  5024.         Other keys may affect Gets(m) as well.  For example, Gets(m),
  5025.         by default, calls Getc which, in turn, usually calls DOS'
  5026.         standard input routine.  If you type control-C or break while
  5027.         read from DOS' standard input it may abort the program.
  5028.  
  5029.         If an error occurs during input (e.g., EOF encountered in
  5030.         the middle of a line) Gets(m) returns the error code in
  5031.         AX.  If no error occurs, Gets(m) preserves AX.
  5032.  
  5033. Include:                  stdlib.a or stdin.a
  5034.  
  5035.  
  5036.  
  5037.  
  5038.  
  5039. Routine:  Scanf
  5040. ---------------
  5041.  
  5042. Category:             Character Input Routine
  5043.  
  5044. Register on entry:    None
  5045.  
  5046. Register on return:   None
  5047.  
  5048. Flags affected:       None
  5049.  
  5050. Example of usage:   
  5051.                       scanf
  5052.                       db      "%i  %h  %^s",0
  5053.                       dd      i, x, sptr
  5054.  
  5055. Description:   * Formatted input from stdlib standard input.
  5056.                * Similar to C's scanf routine.
  5057.                * Converts ASCII to integer, unsigned, character, string, hex,
  5058.          and long values of the above.
  5059.                Scanf provides formatted input in a fashion analogous to
  5060.                printf's output facilities.  Actually, it turns out that scanf
  5061.                is considerably less useful than printf because it doesn't
  5062.                provide reasonable error checking facilities (neither does C's
  5063.                version of this routine).  But for quick and dirty programs 
  5064.                whose input can be controlled in a rigid fashion (or if you're
  5065.                willing to live by "garbage in, garbage out")  scanf provides 
  5066.                a convenient way to get input from the user.  Like printf, the
  5067.                scanf routine expects you to follow the call with a format 
  5068.                string and then a list of (far pointer) memory addresses.  The
  5069.                items in the scanf format string take the following form: %^f,
  5070.                where f represents d, i, x, h, u, c, x, ld, li, lx, or lu.  
  5071.                Like printf, the "^" symbol tells scanf that the address
  5072.                following the format string is the address of a (far) pointer
  5073.                to the data rather than the address of the data location itself.
  5074.                By default, scanf automatically skips any leading whitespace 
  5075.                before attempting to read a numeric value.  You can instruct
  5076.                scanf to skip other characters by placing that character in the
  5077.                format string.  For example, the following call instructs scanf
  5078.            to read three integers separated by commas (and/or whitespace):
  5079.  
  5080.                                  scanf  
  5081.                   db                "%i,%i,%i",0
  5082.                               dd                 i1,i2,i3
  5083.  
  5084.                Whenever scanf encounters a non-blank character in the format
  5085.                string, it will skip that character (including multiple
  5086.                occurrences of that character) if it appears next in the input
  5087.                stream.  Scanf always calls gets to read a new line of text 
  5088.                from stdlib's standard input.  If scanf exhausts the format 
  5089.                list, it ignores any remaining characters on the line.  If
  5090.                scanf exhausts the input line before processing all of the
  5091.                format items, it leaves the remaining variables unchanged.
  5092.                Scanf always deallocates the storage allocated by gets.
  5093.  
  5094.  
  5095. Include:                stdlib.a or stdin.a
  5096.  
  5097.  
  5098. Character Output Routines
  5099. -------------------------
  5100.  
  5101.  
  5102. The stdlib character output routines allow you to print to the 
  5103. standard output device.  Although the processing of non-ASCII 
  5104. characters is undefined, most output devices handle these characters
  5105. properly.  In particular, they can handle return, line feed, back space, 
  5106. and tab.  
  5107.  
  5108. Most of the output routines in the standard library output data 
  5109. through the Putc routine.  They generally use the AX register upon 
  5110. entry and print the character(s) to the standard output device by
  5111. calling DOS by default. The  output is redirectable to the 
  5112. user-written routine.  However, the PutcBIOS routine prints doesn't 
  5113. use DOS.  Instead it uses BIOS routines to print the character in AL 
  5114. using the INT command for teletype-like output. 
  5115.  
  5116. The print routines are similar to those in C, however, they differ
  5117. in their implementation. The print routine returns to the address
  5118. immediately following the terminating byte, therefore, it is important
  5119. to remember to terminate your string with zero or you will print an
  5120. unexpected sequence of characters.
  5121.  
  5122.  
  5123.  
  5124. Routine:  Putc
  5125. --------------
  5126.  
  5127. Category:             Character Output Routine
  5128.  
  5129. Registers on Entry:   AL- character to output
  5130.  
  5131. Registers on Return:  None
  5132.  
  5133. Flags affected:       None
  5134.  
  5135. Example of Usage:
  5136.                        mov     al, 'C'
  5137.                        putc                    ;Prints "C" to std output.
  5138.  
  5139.  
  5140. Description:  Putc is the primitive character output routine.  Most other
  5141.               output routines in the standard library output data through
  5142.               this procedure.  It prints the ASCII character in AL register.  
  5143.               The processing of control codes is undefined although most output
  5144.               routines this routine links to should be able to handle return, 
  5145.               line feed, back space, and tab.  By default, this routine calls
  5146.               DOS to print the character to the standard output device.  The
  5147.               output is redirectable to to user-written routine.
  5148.  
  5149.  
  5150. Include:                stdlib.a or stdout.a
  5151.  
  5152.  
  5153.  
  5154. Routine:  PutCR
  5155. ---------------
  5156.  
  5157. Category:             Character Output Routine 
  5158.  
  5159. Register on entry:    None
  5160.  
  5161. Register on return:   None
  5162.  
  5163. Flags affected:       None
  5164.  
  5165. Example of Usage:     PutCR
  5166.  
  5167.  
  5168. Description:  Using PutCR is an easy way of printing a newline to the stdlib 
  5169.               standard output. It prints a newline (carriage return/line feed) 
  5170.               to the current standard output device.
  5171.  
  5172.  
  5173. Include:                stdlib.a or stdout.a
  5174.  
  5175.  
  5176. Routine: PutcStdOut
  5177. -------------------
  5178.  
  5179. Category:              Character Output Routine
  5180.  
  5181. Registers on Entry:    AL- character to output
  5182.  
  5183. Registers on Return:   None
  5184.  
  5185. Flags Affected:        None
  5186.  
  5187. Example of Usage:
  5188.                        mov AL, 'C'
  5189.                        PutcStdOut        ; Writes "C" to standard output
  5190.  
  5191.  
  5192. Description:  PutcStdOut calls DOS to print the character in AL to the standard
  5193.               output device.  Although processing of non-ASCII characters and
  5194.               control characters is undefined, most output devices handle these
  5195.               characters properly.  In particular, most output devices properly
  5196.               handle return, line feed, back space, and tab.  The output is
  5197.               redirectable via DOS I/O redirection.
  5198.  
  5199.  
  5200. Include:                stdlib.a or stdout.a
  5201.  
  5202.  
  5203.  
  5204. Routine: PutcBIOS
  5205. -----------------
  5206.  
  5207. Category:              Character Output Routine
  5208.  
  5209. Registers on Entry:    AL- character to print
  5210.  
  5211. Registers on Return:   None
  5212.  
  5213. Flags Affected:        None
  5214.  
  5215. Example of Usage:
  5216.                        mov AL, "C"
  5217.                        PutcBIOS
  5218.  
  5219.  
  5220. Description:  PutcBIOS prints the character in AL using the BIOS routines,
  5221.               using INT 10H/AH=14 for teletype-like output.  Output through
  5222.               this routine cannot be redirected; such output is always sent
  5223.               to the video display on the PC (unless, of course, someone has
  5224.               patched INT 10h).  Handles return, line feed, back space, and
  5225.               tab.  Prints other control characters using the IBM Character
  5226.           set.
  5227.  
  5228.  
  5229. Include:         stdlib.a or stdout.a
  5230.  
  5231.  
  5232.  
  5233. Routine: GetOutAdrs
  5234. -------------------
  5235.  
  5236. Category:             Character Output Routine
  5237.  
  5238. Registers on Entry:   None
  5239.  
  5240. Registers on Return:  ES:DI- address of current output routine (called by Putc)
  5241.  
  5242. Flags Affected:       None
  5243.  
  5244. Example of Usage: 
  5245.                       GetOutAdrs
  5246.                       mov word ptr SaveOutAdrs, DI
  5247.                       mov word ptr SaveOutAdrs+2, ES
  5248.  
  5249. Description:  GetOutAdrs gets the address of the current output routine, perhaps
  5250.               so you can save it or see if it is currently pointing at some
  5251.               particular piece of code.  If you want to temporarily redirect
  5252.               the output and then restore the original output routine, consider
  5253.               using PushOutAdrs/PopOutAdrs described later.
  5254.  
  5255. Include:    stdlib.a or stdout.a
  5256.  
  5257.  
  5258.  
  5259.  
  5260. Routine:  SetOutAdrs
  5261. --------------------
  5262.  
  5263. Category:               Character Output Routine
  5264.  
  5265. Registers on Entry:     ES:DI - address of new output routine
  5266.  
  5267. Registers on return:    None 
  5268.  
  5269. Flags affected:         None
  5270.  
  5271. Example of Usage:
  5272.  
  5273.                         mov     es, seg NewOutputRoutine
  5274.                         mov     di, offset NewOutputRoutine
  5275.                         SetOutAdrs
  5276.                         les     di, RoutinePtr
  5277.                         SetOutAdrs
  5278.  
  5279. Description:  This routine redirects the stdlib standard output so that it
  5280.               calls the routine who's address you pass in es:di.  This routine
  5281.               expects the character to be in AL and must preserve all registers.
  5282.               It handles the printable ASCII characters and the four control
  5283.               characters return, line feed, back space, and tab.  (The routine
  5284.               may be modified in the case that you wish to handle these codes
  5285.               in a different fashion.)
  5286.  
  5287.  
  5288. Include:        stdlib.a or stdout.a
  5289.  
  5290.  
  5291. Routine:  PushOutAdrs
  5292. ---------------------
  5293.  
  5294. Category:              Character Output Routine 
  5295.  
  5296. Registers on Entry:    ES:DI- Address of new output routine
  5297.  
  5298. Registers on Return:   None
  5299.  
  5300. Flags Affected:        Carry = 0 if operation is successful
  5301.                        Carry = 1 if there were already 16 items on the stack
  5302.  
  5303. Example of Usage:  
  5304.                        mov  ES, seg NewOutputRoutine
  5305.                        mov  DI, offset NewOutputRoutine
  5306.                        PushOutAdrs
  5307.                           .
  5308.                           .
  5309.                           . 
  5310.                        les  DI, RoutinePtr
  5311.                        PushOutAdrs
  5312.  
  5313.  
  5314. Description:  This routine "pushes" the current output address onto an internal
  5315.               stack and then uses the value in es:di as the current output
  5316.               routine address.  The PushOutAdrs and PopOutAdrs routines let you
  5317.               easily save and redirect the standard output and then restore the
  5318.               original output routine address later on.  If you attempt to push
  5319.           more than 16 items on the stack, PushOutAdrs will ignore your
  5320.               request and return with the carry flag set.  If PushOutAdrs is
  5321.               successful, it will return with the carry flag clear.
  5322.  
  5323.  
  5324. Include:          stdlib.a or stdout.a
  5325.  
  5326.  
  5327.  
  5328. Routine:  PopOutAdrs
  5329. --------------------
  5330.  
  5331. Category:             Character Output Routine 
  5332.  
  5333. Registers on Entry:   None
  5334.  
  5335. Registers on Return:  ES:DI- Points at the previous stdout routine before
  5336.                       the pop
  5337.  
  5338. Flags Affected:       None
  5339.  
  5340. Example of Usage:  
  5341.                       mov ES, seg NewOutputRoutine
  5342.                       mov DI, offset NewOutputRoutine
  5343.                       PushOutAdrs
  5344.                          .
  5345.                          .
  5346.                          .
  5347.                       PopOutAdrs
  5348.  
  5349.  
  5350. Description:  PopOutAdrs undoes the effects of PushOutAdrs.  It pops an item off
  5351.               the internal stack and stores it into the output routine pointer.
  5352.               The previous value in the output pointer is returned in es:di.
  5353.               Defaults to PutcStdOut if you attempt to pop too many items off
  5354.               the stack.
  5355.  
  5356. Include:    stdlib.a or stdout.a
  5357.  
  5358.  
  5359.  
  5360.  
  5361. Routine:  Puts
  5362. --------------
  5363.  
  5364. Category:            Character Output Routine 
  5365.  
  5366. Register on entry:   ES:DI register - contains the address of the string
  5367.  
  5368. Register on return:  None
  5369.  
  5370. Flags affected:      None
  5371.  
  5372. Example of Usage:
  5373.                      les     di, StrToPrt
  5374.                      puts
  5375.                      putcr
  5376.  
  5377.  
  5378. Description:   Puts prints a zero-terminated string whose address appears
  5379.            in es:di.  Each character appearing in the string is printed
  5380.                verbatim.  There are no special escape characters.  Unlike
  5381.                the "C" routine by the same name, puts does not print a
  5382.                newline after printing the string.  Use putcr if you want
  5383.                to print the newline after printing a string with puts.
  5384.  
  5385.  
  5386. Include:        stdlib.a or stdout.a
  5387.  
  5388.  
  5389.  
  5390. Routine:  Puth
  5391. --------------
  5392.  
  5393. Category:             Character Output Routine
  5394.  
  5395. Register on entry:    AL 
  5396.  
  5397. Register on return:   AL
  5398.  
  5399. Flags affected:       None
  5400.  
  5401. Example of Usage:
  5402.                       mov     al, 1fh
  5403.                       puth
  5404.  
  5405.  
  5406. Description:    The Puth routine Prints the value in the AL register as two
  5407.                 hexadecimal digits.  If the value in AL is between 0 and 0Fh, 
  5408.                 puth will print a leading zero.  This routine calls the stdlib
  5409.                 standard output routine (putc) to print all characters.
  5410.  
  5411.  
  5412. Include:        stdlib.a or stdout.a
  5413.  
  5414.  
  5415.  
  5416. Routine:  Putw
  5417. --------------
  5418.  
  5419. Category:             Character Output Routine
  5420.  
  5421. Registers on Entry:   AX- Value to print
  5422.  
  5423. Registers on Return:  None
  5424.  
  5425. Flags Affected:       None
  5426.  
  5427. Example of Usage: 
  5428.                       mov AX, 0f1fh
  5429.                       putw
  5430.  
  5431.  
  5432. Description:  The Putw routine prints the value in the AX register as four
  5433.               hexadecimal digits (including leading zeros if necessary).  
  5434.               This routine calls the stdlib standard output routine (putc) 
  5435.               to print all characters.
  5436.  
  5437. Include:        stdlib.a or stdout.a
  5438.  
  5439.  
  5440.  
  5441. Routine:  Puti
  5442. --------------
  5443.  
  5444. Category:             Character Output Routine
  5445.  
  5446. Registers on Entry:   AX- Value to print
  5447.  
  5448. Registers on Return:  None
  5449.  
  5450. Flags Affected:       None
  5451.  
  5452. Example of Usage: 
  5453.                       mov AX, -1234
  5454.                       puti
  5455.  
  5456.  
  5457. Description:  Puti prints the value in the AX register as a decimal integer.
  5458.               This routine uses the exact number of screen positions required
  5459.           to print the number (including a position for the minus sign, if
  5460.               the number is negative).  This routine calls the stdlib standard
  5461.               output routine (putc) to print all characters.
  5462.  
  5463.  
  5464. Include:        stdlib.a or stdout.a
  5465.  
  5466.  
  5467.  
  5468. Routine:  Putu
  5469. --------------
  5470.  
  5471. Category:             Character Output Routine
  5472.  
  5473. Register on entry:    AX- Unsigned value to print.
  5474.  
  5475. Register on return:   None
  5476.  
  5477. Flags affected:       None
  5478.  
  5479. Example of Usage:
  5480.                       mov     ax, 1234
  5481.                       putu
  5482.  
  5483.  
  5484. Description:  Putu prints the value in the AX register as an unsigned integer.
  5485.               This routine uses the exact number of screen positions required
  5486.               to print the number.  This routine calls the stdlib standard
  5487.               output routine (putc) to print all characters.
  5488.  
  5489.  
  5490. Include:        stdlib.a or stdout.a
  5491.  
  5492.  
  5493.  
  5494.  
  5495. Routine:  Putl
  5496. --------------
  5497.  
  5498. Category:            Character Output Routine
  5499.  
  5500. Register on entry:   DX:AX- Value to print
  5501.  
  5502. Register on return:  None
  5503.  
  5504. Flags affected:      None
  5505.  
  5506. Example of Usage:
  5507.                      mov     dx, 0ffffh
  5508.                      mov     ax, -1234
  5509.                      putl
  5510.  
  5511.  
  5512. Description:   Putl prints the value in the DX:AX registers as an integer.
  5513.                This routine uses the exact number of screen positions
  5514.                required to print the number (including a position for the
  5515.                minus sign, if the number is negative).  This routine calls
  5516.                the stdlib standard output routine (putc) to print all
  5517.                characters.
  5518.  
  5519.  
  5520. Include:        stdlib.a or stdout.a
  5521.  
  5522.  
  5523.  
  5524. Routine:  Putul
  5525. ---------------
  5526.  
  5527. Category:             Character Output Routine
  5528.  
  5529. Register on entry:    DX:AX register
  5530.  
  5531. Register on return:   None
  5532.  
  5533. Flags affected:       None
  5534.  
  5535. Example of Usage:
  5536.                       mov     dx, 12h
  5537.                       mov     ax, 1234
  5538.                       putul
  5539.  
  5540.  
  5541. Description:    Putul prints the value in the DX:AX registers as an unsigned
  5542.                 integer.  This routine uses the exact number of screen
  5543.                 positions required to print the number.  This routine calls 
  5544.         the stdlib standard output routine (putc) to print all
  5545.         characters.
  5546.  
  5547.  
  5548. Include:        stdlib.a or stdout.a
  5549.  
  5550.  
  5551. Routine:  PutISize
  5552. ------------------
  5553.  
  5554. Category:              Character Output Routine
  5555.  
  5556. Registers on Entry:    AX - Integer value to print
  5557.                        CX - Minimum number of print positions to use
  5558.  
  5559. Registers on return:   None
  5560.  
  5561. Flags affected:
  5562.  
  5563. Example of Usage:
  5564.                        mov     cx, 5
  5565.                        mov     ax, I
  5566.                        PutISize
  5567.                            .
  5568.                            . 
  5569.                            .
  5570.                        mov     cx, 12
  5571.                        mov     ax, J
  5572.                        PutISize
  5573.  
  5574.  
  5575. Description:    PutISize prints the signed integer value in AX to the
  5576.                 stdlib standard output device using a minimum of n print
  5577.                 positions.  CX contains n, the minimum field width for the
  5578.                 output value.  The number (including any necessary minus sign)
  5579.         is printed right justified in the output field.
  5580.                 If the number in AX requires more print positions than
  5581.                 specified by CX, PutISize uses however many print positions
  5582.                 are necessary to actually print the number.  If you specify
  5583.                 zero in CX, PutISize uses the minimum number of print positions
  5584.                 required.  Of course, PutI will also use the minimum number
  5585.                 of print positions without disturbing the value in the CX
  5586.                 register.
  5587.  
  5588.                 Note that, under no circumstances, will the number in AX
  5589.                 ever require more than 6 print positions (-32,767 requires
  5590.                 the most print positions).
  5591.  
  5592.  
  5593. Include:        stdlib.a or stdout.a
  5594.  
  5595.  
  5596.  
  5597. Routine:  PutUSize
  5598. ------------------
  5599.  
  5600. Category:              Character Output Routine
  5601.  
  5602. Registers on entry:    AX- Value to print
  5603.                CX- Minimum field width
  5604.  
  5605. Registers on return:   None
  5606.  
  5607. Flags affected:        None
  5608.  
  5609. Example of usage: 
  5610.                        mov     cx, 8
  5611.                        mov     ax, U
  5612.                        PutUSize
  5613.  
  5614.  
  5615. Description:  PutUSize prints the value in AX as an unsigned decimal integer.
  5616.               The minimum field width specified by the value in CX.
  5617.               Like PutISize above except this one prints unsigned values.  
  5618.               Note that the maximum number of print positions required by any 
  5619.           number (e.g., 65,535) is five.
  5620.  
  5621.  
  5622. Include:        stdlib.a or stdout.a
  5623.  
  5624.  
  5625.  
  5626. Routine:  PutLSize
  5627. ------------------
  5628.  
  5629. Category:            Character Output Routine
  5630.  
  5631. Register on entry:   DX:AX-32 bit value to print
  5632.              CX- Minimum field width
  5633.  
  5634. Register on return:  None
  5635.  
  5636. Flags affected:      None
  5637.  
  5638. Example of Usage:
  5639.              mov     cx, 16
  5640.                      mov     dx, word ptr L+2
  5641.                      mov     ax, word ptr L
  5642.                      PutLSize
  5643.  
  5644.  
  5645. Description:   PutLSize is similar to PutISize, except this prints the long 
  5646.                integer value in DX:AX.  Note that there may be as many as 
  5647.                11 print positions (e.g., -1,000,000,000).
  5648.  
  5649. Include:        stdlib.a or stdout.a
  5650.  
  5651.  
  5652.  
  5653.  
  5654. Routine:  PutULSize
  5655. -------------------
  5656.  
  5657.  
  5658. Category:            Character Output Routine
  5659.  
  5660.  
  5661. Register on entry:   AX : DX and CX
  5662.  
  5663.  
  5664. Register on return:  None
  5665.  
  5666.  
  5667. Flags affected:      None
  5668.  
  5669.  
  5670. Example of usage:    mov     cx, 8
  5671.                      mov     dx, word ptr UL+2
  5672.                      mov     ax, word ptr UL
  5673.                      PutULSize
  5674.  
  5675.  
  5676. Description:  Prints the value in DX:AX as a long unsigned decimal integer.
  5677.               Prints the number in a minimum field width specified by the
  5678.               value in CX.  Just like PutLSize above except this one prints
  5679.           unsigned numbers rather than signed long integers.  The largest
  5680.               field width for such a value is 10 print positions.
  5681.  
  5682.  
  5683. Include:        stdlib.a or stdout.a
  5684.  
  5685.  
  5686. Routine:   Print
  5687. ----------------
  5688.  
  5689. Category:             Character Output Routine
  5690.  
  5691. Register on entry:    CS:RET - Return address points at the string to print.
  5692.  
  5693. Register on return:   None
  5694.  
  5695. Flags affected:       None
  5696.  
  5697. Examples of Usage:    print
  5698.                       db      "Print this string to the display device"
  5699.               db      13,10
  5700.                       db      "This appears on a new line"
  5701.                       db      13,10
  5702.                       db      0
  5703.  
  5704.  
  5705. Description:   Print lets you print string literals in a convenient
  5706.                fashion.  The string to print immediately follows the call
  5707.                to the print routine.  The string must contain a
  5708.                zero terminating byte and may not contain any intervening
  5709.                zero bytes.  Since the print routine returns to the address
  5710.                immediately following the zero terminating byte, forgetting
  5711.                this byte or attempting to print a zero byte in the middle
  5712.                of a literal string will cause print to return to an
  5713.                unexpected instruction.  This usually hangs up the machine.
  5714.                Be very careful when using this routine!
  5715.  
  5716.  
  5717. Include:        stdlib.a or stdout.a
  5718.  
  5719.  
  5720. Routine:        Printf
  5721. ----------------------
  5722.  
  5723. Category:             Character Output Routine
  5724.  
  5725. Register on entry:    CS:RET - Return address points at the format string
  5726.  
  5727. Register on return:   None
  5728.  
  5729. Flags affected:       None
  5730.  
  5731. Example of Usage:
  5732.                       printf
  5733.                       db      "Indirect access to i: %^d",13,10,0
  5734.                       dd      IPtr;
  5735.                       printf
  5736.                       db      "A string allocated on the heap: %-\.32^s"
  5737.                       db      13,10,0
  5738.                       dd      SPtr
  5739.  
  5740.  
  5741.  
  5742. Descriptions:   Printf, like its "C" namesake, provides formatted output
  5743.                 capabilities for the stdlib package.  A typical call to printf
  5744.                 always takes the following form:
  5745.  
  5746.                         printf
  5747.                         db              "format string",0
  5748.                         dd              operand1, operand2, ..., operandn
  5749.  
  5750.                 The format string is comparable to the one provided in the
  5751.                 "C" programming language.  For most characters, printf simply
  5752.                 prints the characters in the format string up to the
  5753.                 terminating zero byte.  The two exceptions are characters
  5754.                 prefixed by a backslash ("\") and characters prefixed by a
  5755.                 percent sign ("%").  Like C's printf, stdlib's printf uses
  5756.                 the backslash as an escape character and the percent sign as
  5757.                 a lead-in to a format string.
  5758.  
  5759.         Printf uses the escape character ("\") to print special
  5760.                 characters in a fashion similar to, but not identical to C's
  5761.                 printf.  Stdlib's printf routine supports the following
  5762.                 special characters:
  5763.  
  5764.                 *  r     Print a carriage return (but no line feed)
  5765.                 *  n     Print a new line character (carriage return/line feed).
  5766.                 *  b     Print a backspace character.
  5767.                 *  t     Print a tab character.
  5768.                 *  l     Print a line feed character (but no carriage return).
  5769.                 *  f     Print a form feed character.
  5770.                 *  \     Print the backslash character.
  5771.                 *  %     Print the percent sign character.
  5772.                 *  0xhh  Print ASCII code hh, represented by two hex digits.
  5773.  
  5774.                 C users should note a couple of differences between stdlib's
  5775.                 escape sequences and C's.  First, use "\%" to print a percent
  5776.                 sign within a format string, not "%%".  C doesn't allow the
  5777.                 use of "\%" because the C compiler processes "\%" at compile
  5778.                 time (leaving a single "%" in the object code) whereas printf
  5779.         processes the format string at run-time.  It would see a single
  5780.                 "%" and treat it as a format lead-in character.  Stdlib's
  5781.                 printf, on the other hand, processes both the "\" and "%" and
  5782.                 run-time, therefore it can distinguish "\%".
  5783.  
  5784.                 Strings of the form "\0xhh" must contain exactly two hex
  5785.                 digits.  The current printf routine isn't robust enough to
  5786.                 handle sequences of the form "\0xh" which contain only a
  5787.                 single hex digit.  Keep this in mind if you find printf
  5788.                 chopping off characters after you print a value.
  5789.  
  5790.                 There is absolutely no reason to use any escape character
  5791.                 sequences except "\0x00".  Printf grabs all characters
  5792.                 following the call to printf up to the terminating zero byte
  5793.                 (which is why you'd need to use "\0x00" if you want to print
  5794.                 the null character, printf will not print such values).
  5795.                 Stdlib's printf routine doesn't care how those characters got
  5796.                 there.  In particular, you are not limited to using a single
  5797.                 string after the printf call.  The following is perfectly
  5798.         legal:
  5799.  
  5800.  
  5801.                 printf
  5802.                 db      "This is a string",13,10
  5803.                 db      "This is on a new line",13,10
  5804.                 db      "Print a backspace at the end of this line:"
  5805.                 db      8,13,10,0
  5806.  
  5807.  
  5808.                 Your code will run a tiny amount faster if you avoid the use
  5809.                 of the escape character sequences.  More importantly, the
  5810.                 escape character sequences take at least two bytes.  You can
  5811.                 encode most of them as a single byte by simply embedding the
  5812.                 ASCII code for that byte directly into the code stream.
  5813.                 Don't forget, you cannot embed a zero byte into the code
  5814.                 stream.  A zero byte terminates the format string.  Instead,
  5815.                 use the "\0x00" escape sequence.
  5816.  
  5817.                 Format sequences always between with "%".  For each format
  5818.                 sequence you must provide a far pointer to the associated
  5819.         data immediately following the format string, e.g.,
  5820.  
  5821.                     printf
  5822.                     db      "%i %i",0
  5823.                     dd      i,j
  5824.  
  5825.                 Format sequences take the general form "%s\cn^f" where:
  5826.  
  5827.                 *       "%" is always the "%" character.  Use "\%" if you
  5828.                         actually want to print a percent sign.
  5829.                 *       s is either nothing or a minus sign ("-").
  5830.                 *       "\c" is also optional, it may or may not appear in
  5831.                         the format item.  "c" represents any printable
  5832.                         character.
  5833.                 *       "n" represents a string of 1 or more decimal digits.
  5834.                 *       "^" is just the caret (up-arrow) character.
  5835.                 *       "f" represents one of the format characters: i, d, x,
  5836.                         h, u, c, s, ld, li, lx, or lu.
  5837.  
  5838.                 The "s", "\c", "n", and "^" items are optional, the "%" and
  5839.         "f" items must be present.  Furthermore, the order of these
  5840.                 items in the format item is very important.  The "\c" entry,
  5841.                 for example, cannot precede the "s" entry.  Likewise, the "^"
  5842.                 character, if present, must follow everything except the "f"
  5843.                 character(s).
  5844.  
  5845.                 The format characters i, d, x, h, u, c, s, ld, li, lx, and
  5846.                 lu control the output format for the data.  The i and d
  5847.                 format characters perform identical functions, they tell
  5848.                 printf to print the following value as a 16-bit signed
  5849.                 decimal integer.  The x and h format characters instruct
  5850.                 printf to print the specified value as a 16-bit or 8-bit
  5851.                 hexadecimal value (respectively).  If you specify u, printf
  5852.                 prints the value as a 16-bit unsigned decimal integer.
  5853.                 Using c tells printf to print the value as a single character.
  5854.                 S tells printf that you're supplying the address of a
  5855.                 zero-terminated character string, printf prints that string.
  5856.                 The ld, li, lx, and lu entries are long (32-bit) versions of
  5857.                 d/i, x, and u.  The corresponding address points at a 32-bit
  5858.                 value which printf will format and print to the standard output.
  5859.         The following example demonstrates these format items:
  5860.  
  5861.                 printf
  5862.                 db      "I= %i, U= %u, HexC= %h, HexI= %x, C= %c, "
  5863.                 db      "S= %s",13,10
  5864.                 db      "L= %ld",13,10,0
  5865.                 dd      i,u,c,i,c,s,l
  5866.  
  5867.                 The number of far addresses (specified by operands to the "dd"
  5868.                 pseudo-opcode) must match the number of "%" format items in
  5869.                 the format string.  Printf counts the number of "%" format
  5870.                 items in the format string and skips over this many far
  5871.                 addresses following the format string.  If the number of
  5872.                 items do not match, the return address for printf will be
  5873.                 incorrect and the program will probably hang or otherwise
  5874.                 malfunction.  Likewise (as for the print routine), the format
  5875.                 string must end with a zero byte.  The addresses of the items
  5876.                 following the format string must point directly at the memory
  5877.                 locations where the specified data lies.
  5878.  
  5879.         When used in the format above, printf always prints the
  5880.                 values using the minimum number of print positions for each
  5881.                 operand.  If you want to specify a minimum field width, you
  5882.                 can do so using the "n" format option.  A format item of the
  5883.                 format "%10d" prints a decimal integer using at least ten
  5884.                 print positions.  Likewise, "%16s" prints a string using at
  5885.                 least 16 print positions.  If the value to print requires
  5886.                 more than the specified number of print positions, printf
  5887.                 will use however many are necessary.  If the value to print
  5888.                 requires fewer, printf will always print the specified number,
  5889.                 padding the value with blanks.  Printf will print the value
  5890.                 right justified in the print field (regardless of the data's
  5891.                 type).  If you want to print the value left justified in the
  5892.                 output file, use the "-" format character as a prefix to the
  5893.                 field width, e.g.,
  5894.  
  5895.                 printf
  5896.                 db      "%-17s",0
  5897.                 dd      string
  5898.  
  5899.         In this example, printf prints the string using a 17 character
  5900.                 long field with the string left justified in the output field.
  5901.                 By default, printf blank fills the output field if the value
  5902.                 to print requires fewer print positions than specified by the
  5903.                 format item.  The "\c" format item allows you to change the
  5904.                 padding character.  For example, to print a value, right
  5905.                 justified, using "*" as the padding character you would use
  5906.                 the format item "%\*10d".  To print it left justified you
  5907.                 would use the format item "%-\*10d".  Note that the "-" must
  5908.                 precede the "\*".  This is a limitation of the current
  5909.                 version of the software.  The operands must appear in this
  5910.                 order.  Normally, the address(es) following the printf
  5911.                 format string must be far pointers to the actual data to print.
  5912.                 On occasion, especially when allocating storage on the heap
  5913.                 (using malloc), you may not know (at assembly time) the
  5914.                 address of the object you want to print.  You may have only
  5915.                 a pointer to the data you want to print.  The "^" format
  5916.                 option tells printf that the far pointer following the format
  5917.                 string is the address of a pointer to the data rather than
  5918.                 the address of the data itself.  This option lets you access
  5919.         the data indirectly.
  5920.  
  5921.                 Note: unlike C, stdlib's printf routine does not support
  5922.                 floating point output.  Putting floating point into printf
  5923.         would increase the size of this routine a tremendous amount.
  5924.         Since most people don't need the floating point output
  5925.         facilities, it doesn't appear here.  Check out PRINTFF.
  5926.  
  5927. Include:        stdlib.a or stdout.a
  5928.  
  5929.  
  5930.  
  5931. Routine:  PRINTFF
  5932. -----------------
  5933.  
  5934.  
  5935. Category:             Character Output Routine
  5936.  
  5937. Registers on Entry:   CS:RET- Points at format string and other parameters.
  5938.  
  5939. Registers on Return:  If your program prints floating point values, this
  5940.               routine modifies the floating point accumulator and
  5941.               floating point operand "pseudo-registers" in the
  5942.               floating point package.
  5943.  
  5944. Flags Affected:       None
  5945.  
  5946. Examples of Usage:
  5947.             printff
  5948.             db    "I = %d, R = %7.2f  F = 12.5e  G = 9.2gf\n",0
  5949.             dd    i, r, f, g
  5950.  
  5951. Description:  
  5952.         This code works just like printf except it also allows the
  5953.         output of floating point values.  The output formats are 
  5954.         the following:
  5955.  
  5956.         Single Precision:
  5957.  
  5958.          mm.nnF-    Prints a field width of mm chars with nn digits
  5959.                 appearing after the decimal point.
  5960.  
  5961.          nnE-        Prints a floating point value using scientific
  5962.                 notation in a field width of nn chars.
  5963.  
  5964.         Double Precision:
  5965.  
  5966.          mm.nnGF-    As above, for double precision values.
  5967.          nnGE-        As above, for double precision values.
  5968.  
  5969.         Extended Precision-
  5970.  
  5971.          mm.nnLF-    As above, for extended precision values.
  5972.          nnLE-        As above, for extended precision values.
  5973.  
  5974.  
  5975.         Since PRINTFF supports everything PRINTF does, you should not
  5976.         use both routines in the same program (just use PRINTF).  The
  5977.         PRINTF & PRINTFF macros check for this and will print a warning
  5978.         message if you've included both routines.  Using both will not
  5979.         cause your program to fail, but it will make your program
  5980.         unnecessarily larger.  You should not use PRINTFF unless you
  5981.         really need to print floating point values.  When you use
  5982.         PRINTFF, it forces the linker to load in the entire floating
  5983.         point package, making your program considerably larger.
  5984.  
  5985. Include:                  stdlib.a or fp.a
  5986.  
  5987. String Handling Routines
  5988. ------------------------
  5989.  
  5990. Manipulating text is a major part of many computer applications. Typically,
  5991. strings are inputed and interpreted. This interpretation may involve some
  5992. chores such as extracting certain part of the text, copying it, or comparing
  5993. with other strings.
  5994.  
  5995. The string manipulation routines in C provides various functions. Therefore,
  5996. the stdlib has some C-like string handling functions (e.g. strcpy, strcmp).
  5997. In C a string is an array of characters; similarly, the string are terminated
  5998. by a "0" as a null character. In general, the input strings of these routines
  5999. are pointed by ES:DI. In some routines, the carry flag will be set to indicate
  6000. an error.
  6001.  
  6002. The following string routines take as many as four different forms: strxxx,
  6003. strxxxl, strxxxm, and strxxxlm.  These routines differ in how they store
  6004. the destination string into memory and where they obtain their source strings.
  6005.  
  6006. Routines of the form strxxx generally expect a single source string address
  6007. in ES:DI or a source and destination string in ES:DI & DX:SI.  If these
  6008. routines produce a string, they generally store the result into the buffer
  6009. pointed at by ES:DI upon entry.  They return with ES:DI pointing at the
  6010. first character of the destination string.
  6011.  
  6012. Routines of the form strxxxl have a "literal source string".  A literal
  6013. source string follows the call to the routine in the code stream.  E.g.,
  6014.  
  6015.             strcatl
  6016.             db    "Add this string to ES:DI",0
  6017.  
  6018. Routines of the form strxxxm automatically allocate storage for a source
  6019. string on the heap and return a pointer to this string in ES:DI.
  6020.  
  6021. Routines of the form strxxxlm have a literal source string in the code
  6022. stream and allocate storage for the destination string on the heap.
  6023.  
  6024.  
  6025.  
  6026. Routine:  Strcpy (l)
  6027. --------------------
  6028.  
  6029. Category:             String Handling Routine
  6030.  
  6031. Registers on Entry:   ES:DI - pointer to source string (Strcpy only)
  6032.               CS:RET - pointer to  source  string (Strcpy1 only)
  6033.               DX:SI - pointer to destination string
  6034.  
  6035.  
  6036. Registers on return:  ES:DI - points at the destination string
  6037.  
  6038.  
  6039. Flags affected:          None
  6040.  
  6041.  
  6042. Example of Usage:
  6043.               mov     dx, seg Dest
  6044.               mov     si, offset Dest
  6045.               mov     di, seg Source
  6046.               mov     es, di
  6047.               mov     si, offset Source
  6048.               Strcpy
  6049.  
  6050.               mov     dx, seg Dest
  6051.               mov     si, offset Dest
  6052.               Strcpyl
  6053.               db      "String to copy",0
  6054.  
  6055.  
  6056. Description:  Strcpy is used to copy a zero-terminated string from one
  6057.           location to another.  ES:DI points at the source string,
  6058.           DX:SI points at the destination address.  Strcpy copies all
  6059.           bytes, up to and including the zero byte, from the source
  6060.           address to the destination address.  The target buffer must
  6061.           be large enough to hold the string.  Strcpy performs no error
  6062.           checking on the size of the destination buffer.
  6063.  
  6064.           Strcpyl copies the  zero-terminated string immediately following
  6065.           the call instruction to the destination address specified by
  6066.           DX:SI.  Again, this routine expects you to ensure that the
  6067.           taraget buffer is large enough to hold the result.
  6068.  
  6069.           Note: There are no "Strcpym" or "Strcpylm" routines.  The
  6070.           reason is simple: "StrDup" and "StrDupl" provide these functions
  6071.           using names which are familiar to MSC and Borland C users.
  6072.  
  6073. Include:              stdlib.a or strings.a
  6074.  
  6075.  
  6076. Routine:  StrDup (l)
  6077. --------------------
  6078.  
  6079. Category:            String Handling Routine
  6080.  
  6081. Register on entry:   ES:dI - pointer to source string (StrDup
  6082.              only).  CS:RET - Pointer to source string
  6083.              (StrDupl only).
  6084.  
  6085. Register on return:  ES:DI - Points at the destination string
  6086.              allocated on heap.  Carry=0 if operation
  6087.              successful.  Carry=0 if insufficient
  6088.              memory for new string.
  6089.  
  6090. Flags affected:      Carry flag
  6091.  
  6092. Example of usage:
  6093.              StrDupl
  6094.              db "String for StrDupl",0
  6095.              jc  MallocError
  6096.              mov word ptr Dest1, di
  6097.              mov word ptr Dest1+2, es  ;create another
  6098.                            ;copy of this
  6099.                            ;string. Note
  6100.                            ;that es:di points
  6101.                            ;at Dest1 upon
  6102.                            ;entry to StrDup,
  6103.                            ;but it points at
  6104.                            ;the new string on
  6105.                            ;exit
  6106.              StrDup
  6107.              jc MallocError
  6108.              mov word ptr Dest2, di
  6109.              mov word ptr Dest2+2, es
  6110.  
  6111.  
  6112. Description:  StrDup and StrDupl duplicate strings.  You pass them
  6113.           a pointer to the string (in es:di for strdup, via
  6114.           the return address for strdupl) and they allocate
  6115.           sufficient storage on the heap for a copy of this
  6116.           string.  Then these two routines copy their source
  6117.           strings to the newly allocated storage and return
  6118.           a pointer to the new string in ES:DI.
  6119.  
  6120.  
  6121. Include:             stdlib.a or strings.a
  6122.  
  6123.  
  6124. Routine:  Strlen
  6125. ----------------
  6126.  
  6127. Category:            String Handling Routine
  6128.  
  6129. Registers on entry:  ES:DI - pointer to source string.
  6130.  
  6131. Register on return:  CX - length of specified string.
  6132.  
  6133. Flags Affected:      None
  6134.  
  6135. Examples of Usage:
  6136.              les   di, String
  6137.              strlen
  6138.              mov   sl, cx
  6139.              printf
  6140.              db   "Length of '%s' is %d\n",0
  6141.              dd   String, sl
  6142.  
  6143.  
  6144. Description:  Strlen computes the length of the string whose address
  6145.           appears in ES:DI.  It returns the number of characters
  6146.           up to, but not including, the zero terminating byte.
  6147.  
  6148. Include:             stdlib.a or strings.a
  6149.  
  6150.  
  6151. Routine:  Strcat (m,l,ml)
  6152. -------------------------
  6153.  
  6154. Category:             String Handling Routine
  6155.  
  6156. Registers on Entry:   ES:DI- Pointer to first string
  6157.               DX:SI- Pointer to second string (Strcat and Strcatm only)
  6158.  
  6159.  
  6160. Registers on Return:  ES:DI- Pointer to new string (Strcatm and Strcatml only)
  6161.  
  6162. Flags Affected:       Carry = 0 if no error
  6163.               Carry = 1 if insufficient memory (Strcatm and Strcatml
  6164.                             only)
  6165.  
  6166.  
  6167. Example of Usage:     les  DI, String1
  6168.               mov  DX, seg String2
  6169.               lea  SI, String2
  6170.               Strcat                   ; String1 <- String1 + String2
  6171.  
  6172.               les  DI, String1
  6173.               Strcatl                  ; String1 <- String1 +
  6174.               db  "Appended String",0  ;            "Appended String",0
  6175.  
  6176.  
  6177.               les  DI, String1
  6178.               mov  DX, seg String2
  6179.               lea  SI, String2
  6180.               Strcatm                  ; NewString <- String1 + String2
  6181.               puts
  6182.               free
  6183.  
  6184.               les  DI, String1
  6185.               Strcatml                 ; NewString <- String1 +
  6186.               db  "Appended String",0  ;         "Appended String",0
  6187.               puts
  6188.               free
  6189.  
  6190.  
  6191. Description:  These routines concatenate two strings together.  They differ
  6192.           mainly in the location of their source and destination operands.
  6193.  
  6194.           Strcat concatenates the string pointed at by DX:SI to the end of
  6195.           the string pointed at by ES:DI in memory.  Both strings must be
  6196.           zero-terminated.  The buffer pointed at by ES:DI must be large
  6197.           enough to hold the resulting string.  Strcat does NOT perform
  6198.           bounds checking on the data.
  6199.  
  6200.           ( continued on next page )
  6201.  
  6202.  
  6203.  
  6204.  
  6205.  
  6206.  
  6207.  
  6208. Routine:  Strcat (m,l,ml)   ( continued )
  6209. -----------------------------------------
  6210.  
  6211.  
  6212.           Strcatm computes the length of the two strings pointed at by ES:DI
  6213.           and DX:SI and attempts to allocate this much storage on the heap.
  6214.           If it is not successful, Strcatm returns with the Carry flag set,
  6215.           otherwise it copies the string pointed at by ES:DI to the heap,
  6216.           concatenates the string DX:SI points at to the end of this string
  6217.           on the heap, and returns with the Carry flag clear and ES:DI
  6218.           pointing at the new (concatenated) string on the heap.
  6219.  
  6220.           Strcatl and Strcatml work just like Strcat and Strcatm except you
  6221.           supply the second string as a literal constant immediately AFTER
  6222.           the call rather than pointing DX:SI at it (see examples above).
  6223.  
  6224.  
  6225. Include:             stdlib.a or strings.a
  6226.  
  6227.  
  6228. Routine:  Strchr
  6229. ----------------
  6230.  
  6231. Category:            String Handling Routine
  6232.  
  6233. Register on entry:   ES:DI- Pointer to string.
  6234.             AL- Character to search for.
  6235.  
  6236. Register on return:  CX- Position (starting at zero)
  6237.              where Strchr found the character.
  6238.  
  6239. Flags affected:      Carry=0 if Strchr found the character.
  6240.              Carry=1 if the character was not present
  6241.                  in the string.
  6242.  
  6243. Example of usage:
  6244.              les di, String
  6245.              mov al, Char2Find
  6246.              Strchr
  6247.              jc  NotPresent
  6248.              mov CharPosn, cx
  6249.  
  6250.  
  6251. Description:  Strchr locates the first occurrence of a character within a
  6252.           string.  It searches through the zero-terminated string pointed
  6253.           at by es:di for the character passed in AL. If it locates the
  6254.           character, it returns the position of that character to the CX
  6255.           register.  The first character in the string corresponds to the
  6256.           location zero.  If the character is not in the string, Strchr
  6257.           returns the carry flag set.  CX's value is undefined in that
  6258.           case.  If Strchr locates the character in the string, it
  6259.           returns with the carry clear.
  6260.  
  6261.  
  6262. Include:             stdlib.a or strings.a
  6263.  
  6264.  
  6265. Routine:  Strstr (l)
  6266. --------------------
  6267.  
  6268. Category:            String Handling Routine
  6269.  
  6270. Register on entry:   ES:DI - Pointer to string.
  6271.              DX:SI - Pointer to substring(strstr).
  6272.              CS:RET - Pointer to substring (strstrl).
  6273.  
  6274. Register on return:  CX - Position (starting at zero)
  6275.              where Strstr/Strstrl found the
  6276.              character.  Carry=0 if Strstr/
  6277.              Strstrl found the character.
  6278.              Carry=1 if the character was not
  6279.              present in the string.
  6280.  
  6281. Flags affected:      Carry flag
  6282.  
  6283. Example of usage :
  6284.              les di, MainString
  6285.              lea si, Substring
  6286.              mov dx, seg Substring
  6287.              Strstr
  6288.              jc NoMatch
  6289.              mov i, cx
  6290.              printf
  6291.              db "Found the substring '%s' at location %i\n",0
  6292.              dd Substring, i
  6293.  
  6294.  
  6295. Description:  Strstr searches for the position of a substring
  6296.           within another string.  ES:DI points at the
  6297.           string to search through, DX:SI points at the
  6298.           substring.  Strstr returns the index into ES:DI's
  6299.           string where DX:SI's string is found.  If the
  6300.           string is found, Strstr returns with the carry
  6301.           flag clear and CX contains the (zero based) index
  6302.           into the string.  If Strstr cannot locate the
  6303.           substring within the string ES:DI points at, it
  6304.           returns the carry flag set.  Strstrl works just
  6305.           like Strstr except it excepts the substring to
  6306.           search for immediately after the call instruction
  6307.           (rather than passing this address in DX:SI).
  6308.  
  6309.  
  6310. Include:              stdlib.a or strings.a
  6311.  
  6312.  
  6313. Routine:  Strcmp (l)
  6314. --------------------
  6315.  
  6316. Category:            String Handling Routine
  6317.  
  6318. Registers on entry:  ES:DI contains the address of the first string
  6319.              DX:SI contains the address of the second string (strcmp)
  6320.              CS:RET (contains the address of the substring (strcmpl)
  6321.  
  6322. Register on return:  CX (contains the position where the two strings differ)
  6323.  
  6324. Flags affected:      Carry flag and zero flag (string1 > string2 if C + Z = 0)
  6325.                      (string1 < string2 if C = 1)
  6326.  
  6327. Example of Usage:
  6328.              les     di, String1
  6329.              mov     dx, seg String2
  6330.              lea     si, String2
  6331.              strcmp
  6332.              ja        OverThere
  6333.  
  6334.              les     di, String1
  6335.              strcmpl
  6336.              db     "Hello",0
  6337.              jbe     elsewhere
  6338.  
  6339.  
  6340.  
  6341. Description:  Strcmp compares the first strings pointed by ES:DI with
  6342.           the second string pointed by DX:SI. The carry and zero flag
  6343.           will contain the corresponding result. So unsigned branch
  6344.           instructions such as JA or JB is recommended. If string1
  6345.           equals string2, strcmp will return with CX containing the
  6346.           offset of the zero byte in the two strings.
  6347.  
  6348.           Strcmpl compares the first string pointed by ES:DI with
  6349.           the substring pointed by CS:RET. The carry and zero flag
  6350.           will contain the corresponding result. So unsigned branch
  6351.           instructions such as JA or JB are recommended. If string1
  6352.           equals to the substring, strcmp will return with CX
  6353.           containing the offset of the zero byte in the two strings.
  6354.  
  6355. Include:             stdlib.a or strings.a
  6356.  
  6357.  
  6358. Routine:  Stricmp (l)
  6359. ---------------------
  6360.  
  6361. Category:            String Handling Routine
  6362.  
  6363. Registers on entry:  ES:DI contains the address of the first string
  6364.              DX:SI contains the address of the second string (stricmp)
  6365.              CS:RET (contains the address of the substring (stricmpl)
  6366.  
  6367. Register on return:  CX (contains the position where the two strings differ)
  6368.  
  6369. Flags affected:      Carry flag and zero flag (string1 > string2 if C + Z = 0)
  6370.                      (string1 < string2 if C = 1)
  6371.  
  6372. Example of Usage:
  6373.              les     di, String1
  6374.              mov     dx, seg String2
  6375.              lea     si, String2
  6376.              stricmp
  6377.              ja        OverThere
  6378.  
  6379.              les     di, String1
  6380.              stricmpl
  6381.              db     "Hello",0
  6382.              jbe     elsewhere
  6383.  
  6384.  
  6385.  
  6386. Description:    This routine is virtually identical to strcmp (l) except it
  6387.         ignores case when comparing the strings.
  6388.  
  6389. Include:             stdlib.a or strings.a
  6390.  
  6391.  
  6392. Routine:  Strupr (m)
  6393. --------------------
  6394.  
  6395. Category:            String Handling Routine
  6396.              Conversion Routine
  6397.  
  6398. Register on entry:   ES:DI (contains the pointer to input string)
  6399.  
  6400. Register on return:  ES:DI (contains the pointer to input string
  6401.                with characters converted to upper case)
  6402.                Note: struprm allocates storage for a new
  6403.                string on the heap and returns the pointer
  6404.                to this routine in ES:DI.
  6405.  
  6406. Flags affected:      Carry = 1 if memory allocation error (Struprm only).
  6407.  
  6408. Example of Usage:
  6409.              les     di, lwrstr1
  6410.              strupr
  6411.              puts
  6412.  
  6413.              mov        di, seg StrWLwr
  6414.              mov    es, di
  6415.              lea    di, StrWLwr
  6416.              struprm
  6417.              puts
  6418.              free
  6419.  
  6420.  
  6421. Description:  Strupr converts the input string pointed by ES:DI to
  6422.           upper case.  It will actually modify the string you pass
  6423.           to it.
  6424.  
  6425.           Struprm first makes a copy of the string on the heap and
  6426.           then converts the characters in this new string to upper
  6427.           case.  It returns a pointer to the new string in ES:DI.
  6428.  
  6429. Include:             stdlib.a or strings.a
  6430.  
  6431.  
  6432. Routine:  Strlwr (m)
  6433. --------------------
  6434.  
  6435. Category:            String Handling Routine
  6436.              Conversion Routine
  6437.  
  6438. Register on entry:   ES:DI (contains the pointer to input string)
  6439.  
  6440. Register on return:  ES:DI (contains the pointer to input string
  6441.                with characters converted to lower case).
  6442.  
  6443. Flags affected:      Carry = 1 if memory allocation error (strlwrm only)
  6444.  
  6445.  
  6446. Example of Usage:
  6447.              les di, uprstr1
  6448.              strlwr
  6449.              puts
  6450.  
  6451.              mov        di, seg StrWLwr
  6452.              mov    es, di
  6453.              lea    di, StrWLwr
  6454.              strlwrm
  6455.              puts
  6456.              free
  6457.  
  6458.  
  6459.  
  6460.  
  6461. Description:  Strlwr converts the input string pointed by ES:DI to
  6462.           lower case. It will actually modify the string you pass
  6463.           to it.
  6464.  
  6465.           Strlwrm first copies the characters onto the heap and then
  6466.           returns a pointer to this string after converting all the
  6467.           alphabetic characters to lower case.
  6468.  
  6469.  
  6470. Include:             stdlib.a or strings.a
  6471.  
  6472.  
  6473.  
  6474. Routine:  Strset (m)
  6475. --------------------
  6476.  
  6477. Category:            String Handling Routine
  6478.  
  6479. Register on entry:   ES:DI contains the pointer to input string (StrSet only)
  6480.              AL    contains the character to copy
  6481.              CX    contains number of characters to allocate for
  6482.                the string (Strsetm only)
  6483.  
  6484. Register on return:  ES:DI pointer to newly allocated string (Strsetm only)
  6485.  
  6486. Flags affected:      Carry set if memory allocation error (Strsetm only)
  6487.  
  6488. Example of Usage:
  6489.              les     di, string1
  6490.              mov    al, " "        ;Blank fill string.
  6491.              Strset
  6492.  
  6493.              mov     cx, 32
  6494.              mov    al, "*"        ;Create a new string w/32
  6495.              Strsetm            ; asterisks.
  6496.              puts
  6497.              free
  6498.  
  6499.  
  6500. Description:  Strset overwrites the data on input string pointed by
  6501.           ES:DI with the character on AL.
  6502.  
  6503.           Strsetm creates a new string on the heap with the number
  6504.           of characters specified in CX.  All characters in the string
  6505.           are initialized with the value in AL.
  6506.  
  6507. Include:             stdlib.a or strings.a
  6508.  
  6509.  
  6510. Routine:  Strspan (l)
  6511. ---------------------
  6512.  
  6513. Category:             String Handling Routine
  6514.  
  6515. Registers on Entry:   ES:DI - Pointer to string to scan
  6516.               DX:SI - Pointer to character set (Strspan only)
  6517.               CS:RET- Pointer to character set (Strspanl only)
  6518.  
  6519. Registers on Return:  CX- First position in scanned string which does not
  6520.               contain one of the characters in the character set
  6521.  
  6522. Flags Affected:       None
  6523.  
  6524. Example of Usage:
  6525.               les  DI, String
  6526.               mov  DX, seg CharSet
  6527.               lea  SI, CharSet
  6528.               Strspan           ; find first position in String with a
  6529.               mov i, CX         ;                  char not in CharSet
  6530.               printf
  6531.               db  "The first char which is not in CharSet "
  6532.               db  "occurs at position %d in String.\n",0
  6533.               dd  i
  6534.  
  6535.               les  DI, String
  6536.               Strspanl          ; find first position in String which
  6537.               db   "aeiou",0    ; is not a vowel
  6538.               mov  j, CX
  6539.               printf
  6540.               db  "The first char which is not a vowel "
  6541.               db  "occurs at position %d in String.\n",0
  6542.               dd  j
  6543.  
  6544.  
  6545. Description:  Strspan(l) scans a string, counting the number of characters which
  6546.           are present in a second string (which represents a character set).
  6547.           ES:DI points at a zero-terminated string of characters to scan.
  6548.           DX:SI (strspan) or CS:RET (strspanl) points at another zero-
  6549.           terminated string containing the set of characters to compare
  6550.           against.  The position of the first character in the string
  6551.           pointed to by ES:DI which is NOT in the character set is returned.
  6552.           If all the characters in the string are in the character set, the
  6553.           position of the zero-terminating byte will be returned.
  6554.  
  6555.           Although strspan and (especially) strspanl are very compact and
  6556.           convenient to use, they are not particularly efficient.  The
  6557.           character set routines provide a much faster alternative at the
  6558.           expense of a little more space.
  6559.  
  6560.  
  6561. Include:               stdlib.a or strings.a
  6562.  
  6563.  
  6564. Routine:  Strcspan, Strcspanl
  6565. -----------------------------
  6566.  
  6567. Category:             String Handling Routine
  6568.  
  6569. Registers on Entry:   ES:DI - Pointer to string to scan
  6570.               DX:SI - Pointer to character set (Strcspan only)
  6571.               CS:RET- Pointer to character set (Strcspanl only)
  6572.  
  6573. Registers on Return:  CX- First position in scanned string which contains one
  6574.               of the characters in the character set
  6575.  
  6576. Flags Affected:       None
  6577.  
  6578. Example of Usage:
  6579.               les  DI, String
  6580.               mov  DX, seg CharSet
  6581.               lea  SI, CharSet
  6582.               Strcspan          ; find first position in String with a
  6583.               mov i, CX         ;                      char in CharSet
  6584.               printf
  6585.               db  "The first char which is in CharSet "
  6586.               db  "occurs at position %d in String.\n",0
  6587.               dd  i
  6588.  
  6589.               les  DI, String
  6590.               Strcspanl         ; find first position in String which
  6591.               db   "aeiou",0    ; is a vowel.
  6592.               mov  j, CX
  6593.               printf
  6594.               db  "The first char which is a vowel occurs "
  6595.               db  "at position %d in String.\n",0
  6596.               dd  j
  6597.  
  6598.  
  6599. Description:  Strcspan(l) scans a string, counting the number of characters
  6600.           which are NOT present in a second string (which represents a
  6601.           character set).  ES:DI points at a zero-terminated string of
  6602.           characters to scan.  DX:SI (strcspan) or CS:RET (strcspanl) points
  6603.           at another zero-terminated string containing the set of characters
  6604.           to compare against.  The position of the first character in the
  6605.           string pointed to by ES:DI which is in the character set is
  6606.           returned.  If all the characters in the string are not in the
  6607.           character set, the position of the zero-terminating byte will be
  6608.           returned.
  6609.  
  6610.           Although strcspan and strcspanl are very compact and convenient to
  6611.           use, they are not particularly efficient.  The character set
  6612.           routines provide a much faster alternative at the expense of a
  6613.           little more space.
  6614.  
  6615. Include:              stdlib.a or strings.a
  6616.  
  6617.  
  6618. Routine:  StrIns (m,l,ml)
  6619. -------------------------
  6620.  
  6621. Category:             String Handling Routine
  6622.  
  6623. Registers on Entry:   ES:DI - Pointer to destination string (to insert into)
  6624.               DX:SI - Pointer to string to insert
  6625.                       (StrIns and StrInsm only)
  6626.               CX    - Insertion point in destination string
  6627.  
  6628. Registers on Return:  ES:DI - Pointer to new string (StrInsm and StrInsml only)
  6629.  
  6630. Flags Affected:       Carry = 0 if no error
  6631.               Carry = 1 if insufficient memory
  6632.                    (StrInsm and StrInsml only)
  6633.  
  6634.  
  6635. Example of Usage:
  6636.               les  DI, DestStr
  6637.               mov  DX, word ptr SrcStr+2
  6638.               mov  SI, word ptr SrcStr
  6639.               mov  CX, 5
  6640.               StrIns     ; Insert SrcStr before the 6th char of DestStr
  6641.  
  6642.               les  DI, DestStr
  6643.               mov  CX, 2
  6644.               StrInsl    ; Insert "Hello" before the 3rd char of DestStr
  6645.               db  "Hello",0
  6646.  
  6647.               les  DI, DestStr
  6648.               mov  DX, word ptr SrcStr+2
  6649.               mov  SI, word ptr SrcStr
  6650.               mov  CX, 11
  6651.               StrInsm      ; Create a new string by inserting SrcStr
  6652.                    ;         before the 12th char of DestStr
  6653.               puts
  6654.               putcr
  6655.               free
  6656.  
  6657.  
  6658. Description:  These routines insert one string into another string.  ES:DI
  6659.           points at the string into which you want to insert another.  CX
  6660.           contains the position (or index) where you want the string
  6661.           inserted.  This index is zero-based, so if CX contains zero, the
  6662.           source string will be inserted before the first character in the
  6663.           destination string.  If CX contains a value larger than the size
  6664.           of the destination string, the source string will be appended to
  6665.           the destination string.
  6666.  
  6667.           StrIns inserts the string pointed at by DX:SI into the string
  6668.           pointed at by ES:DI at position CX.  The buffer pointed at by
  6669.           ES:DI must be large enough to hold the resulting string.  StrIns
  6670.           does NOT perform bounds checking on the data.
  6671.  
  6672.      ( continued on next page )
  6673.  
  6674.  
  6675. Routine:  StrIns (m,l,ml)   ( continued )
  6676. -----------------------------------------
  6677.  
  6678.           StrInsm does not modify the source or destination strings, but
  6679.           instead attempts to allocate a new buffer on the heap to hold the
  6680.           resulting string.  If it is not successful, StrInsm returns with
  6681.           the Carry flag set, otherwise the resulting string is created and
  6682.           its address is returned in the ES:DI registers.
  6683.  
  6684.           StrInsl and StrInsml work just like StrIns and StrInsm except you
  6685.           supply the second string as a literal constant immediately AFTER
  6686.           the call rather than pointing DX:SI at it (see examples above).
  6687.  
  6688.  
  6689.  
  6690. Routine:  StrDel, StrDelm
  6691. -------------------------
  6692.  
  6693. Category:              String Handling Routine
  6694.  
  6695. Registers on Entry:    ES:DI -  pointer to string
  6696.                CX - deletion point in  string
  6697.                AX - number of characters to delete
  6698.  
  6699. Registers on return:   ES:DI - pointer to new string (StrDelm only)
  6700.  
  6701. Flags  affected:       Carry = 1 if memory allocation error,  0 if okay
  6702.                (StrDelm only).
  6703.  
  6704. Example of Usage:
  6705.                les     di,  Str2Del
  6706.                mov     cx,  3          ; Delete starting at 4th char
  6707.                mov     ax,  5          ; Delete five characters
  6708.                StrDel                  ; Delete in place
  6709.  
  6710.                les     di,  Str2Del2
  6711.                mov     cx,  5
  6712.                mov     ax,  12
  6713.                StrDelm
  6714.                puts
  6715.                free
  6716.  
  6717.  
  6718. Description:  StrDel deletes characters from a string.  It works by computing
  6719.           the beginning and end of the deletion point.  Then it copies all
  6720.           the characters from the end of the deletion point to the end of
  6721.           the string (including the zero byte) to the beginning of the
  6722.           deletion point.  This covers up (thereby effectively deleting)
  6723.           the undesired characters in the string.
  6724.  
  6725.           Here are two degenerate cases to worry about -- 1) when you
  6726.           specify a deletion point which is beyond the end of the string;
  6727.           and 2) when the deletion point is within the string but the
  6728.           length of the deletion takes you beyond the end of the string.
  6729.           In the first case StrDel simply ignores the deletion request.  It
  6730.           does not modify the original string.  In the second case,
  6731.           StrDel simply deletes everything from the deletion point to the
  6732.           end of the string.
  6733.  
  6734.           StrDelm works just like StrDel except it does not delete the
  6735.           characters in place.  Instead, it creates a new string on the
  6736.           heap consisting of the characters up to the deletion point and
  6737.           those following the characters to delete.  It returns a pointer
  6738.           to the new string on the heap in ES:DI, assuming that it
  6739.           properly allocated the storage on the heap.
  6740.  
  6741. Include:               stdlib.a or strings.a
  6742.  
  6743.  
  6744. Routine:  StrTrim (m)
  6745. ---------------------
  6746.  
  6747. Category:              String Handling Routine
  6748.  
  6749. Registers on Entry:    ES:DI -  pointer to string
  6750.  
  6751. Registers on return:   ES:DI - pointer to string (new string if StrTrimm)
  6752.  
  6753. Flags  affected:       Carry = 1 if memory allocation error,  0 if okay
  6754.                (StrTrimm only).
  6755.  
  6756. Example of Usage:
  6757.                les     di,  Str2Trim
  6758.                StrTrim                 ; Delete in place
  6759.                puts
  6760.  
  6761.                les     di,  Str2Trim2
  6762.                StrTrimm
  6763.                puts
  6764.                free
  6765.  
  6766.  
  6767. Description:    StrTrim (m) removes trailing spaces from a string.  StrTrim
  6768.         removes the space in the specified string (by backing up the
  6769.         zero terminating byte in the string.  StrTrimm creates a new
  6770.         copy of the string (on the heap) without the trailing spaces.
  6771.  
  6772. Include:               stdlib.a or strings.a
  6773.  
  6774.  
  6775. Routine:  StrBlkDel (m)
  6776. -----------------------
  6777.  
  6778. Category:              String Handling Routine
  6779.  
  6780. Registers on Entry:    ES:DI -  pointer to string
  6781.  
  6782. Registers on return:   ES:DI - pointer to string (new string if StrBlkDelm)
  6783.  
  6784. Flags  affected:       Carry = 1 if memory allocation error,  0 if okay
  6785.                (StrBlkDelm only).
  6786.  
  6787. Example of Usage:
  6788.                les     di,  Str2Trim
  6789.                StrBlkDel        ; Delete in place
  6790.                puts
  6791.  
  6792.                les     di,  Str2Trim2
  6793.                StrBlkDelm
  6794.                puts
  6795.                free
  6796.  
  6797.  
  6798. Description:    StrBlkDel (m) removes leading spaces from a string.  StrBlkDel
  6799.         removes the space in the specified string, modifying that
  6800.         string.  StrBlkDelm creates a new copy of the string (on the
  6801.         heap) without the leading spaces.
  6802.  
  6803. Include:               stdlib.a or strings.a
  6804.  
  6805.  
  6806. Routine:  StrRev, StrRevm
  6807. -------------------------
  6808.  
  6809. Author:               Michael Blaszczak (.B  ekiM)
  6810.  
  6811. Category:             String Handling Routine
  6812.  
  6813. Registers on Entry:   ES:DI - pointer to string
  6814.  
  6815. Registers on return:  ES:DI - pointer to new string (StrRevm only).
  6816.  
  6817. Flags affected:       Carry  = 1 if memory allocation error, 0 if okay
  6818.               (StrRevm only).
  6819.  
  6820. Example of Usage:
  6821.  
  6822. Description:  StrRev reverses the characters in a string.  StrRev reverses,
  6823.           in place, the characters in the string that ES:SI points at.
  6824.           StrRevm creates a new string on the heap (which contains the
  6825.           characters in the string ES:DI points at, only reversed) and
  6826.           returns a pointer to the new string in ES:DI.  If StrRevm
  6827.           cannot allocate sufficient memory for the string, it returns
  6828.           with the carry flag set.
  6829.  
  6830.  
  6831. Include:              stdlib.a or strings.a
  6832.  
  6833. Routine:  StrBDel (m)
  6834. ---------------------
  6835.  
  6836. Author:               Randall Hyde
  6837.  
  6838. Category:             String Handling Routine
  6839.  
  6840. Registers on Entry:   ES:DI - pointer to string
  6841.  
  6842. Registers on return:  ES:DI - pointer to new string (StrBDelm only).
  6843.  
  6844. Flags affected:       Carry  = 1 if memory allocation error, 0 if okay
  6845.               (StrBDelm only).
  6846.  
  6847. Example of Usage:
  6848.  
  6849. Description:    StrBDel(m) deletes leading blanks from a string.  StrBDel
  6850.         operates on the string in place, StrBDelm creates a copy
  6851.         (on the heap) of the string without the leading blanks.
  6852.  
  6853. Include:              stdlib.a or strings.a
  6854.  
  6855.  
  6856. Routine:  ToHex
  6857. ---------------
  6858.  
  6859. Category:             String Handling Routine/ Conversion Routine
  6860.  
  6861. Registers on Entry:   ES:DI - pointer to byte array
  6862.               BX-     memory base address for bytes
  6863.               CX-     number of entries in byte array
  6864.  
  6865. Registers on return:  ES:DI - pointer to Intel Hex format string.
  6866.  
  6867. Flags affected:       Carry  = 1 if memory allocation error, 0 if okay
  6868.  
  6869.  
  6870. Example of Usage:
  6871.  
  6872.         mov    bx, 100h    ;Put data at address 100h in hex file.
  6873.         mov    cx, 10h        ;Total of 16 bytes in this array.
  6874.         les    di, Buffer    ;Pointer to data bytes
  6875.         ToHex            ;Convert to Intel HEX string format.
  6876.         puts            ;Print it.
  6877.  
  6878. Description:
  6879.  
  6880. ToHex converts a stream of binary values to Intel Hex format.  Intel HEX format
  6881. is a common ASCII data interchange format for binary data.  It takes the
  6882. following form:
  6883.  
  6884.     : BB HHLL RR DDDD...DDDD SS <cr> <lf>
  6885.  
  6886. (Note:spaces were added for clarity, they are not actually present in the
  6887. hex string)
  6888.  
  6889. BB is a pair of hex digits which represent the number of data bytes (The DD
  6890. entries) and is the value passed in CX.
  6891.  
  6892. HHLL is the hexadecimal load address for these data bytes (passed in BX).
  6893.  
  6894. RR is the record type.  ToHex always produces data records with the RR field
  6895. containing "00".  If you need to output other field types (usually just an
  6896. end record) you must create that string yourself.  ToHex will not do it.
  6897.  
  6898. DD...DD is the actual data in hex form.  This is the number of bytes specified
  6899. in the BB field.
  6900.  
  6901. SS is the two's complement of the checksum (which is the sum of the binary
  6902. values of the BB, HH, LL, RR, and all DD fields).
  6903.  
  6904. This routine allocates storage for the string on the heap and returns a pointer
  6905. to that string in ES:DI.
  6906.  
  6907. Include:              stdlib.a or strings.a
  6908.  
  6909. Utility Routines
  6910. ----------------
  6911.  
  6912. The following routines are all Utility Routines.  The first routines listed
  6913. below compute the number of print positions required by a 16-bit and 32-bit
  6914. signed and unsigned integer value.  UlSize is like the LSize except it treats
  6915. the value in DX:AX as an unsigned long integer.  The next set of routines in
  6916. this section check the character in the AL register to see whether it is a
  6917. hexidecimal digit, if it alphabetic, if it is a lower case alphabetic, if it
  6918. is a upper case alphabetic, and if it is numeric.  Then there are some
  6919. miscellaneous routines (macros) which process command line parameters, invoke
  6920. DOS and exit the program.
  6921.  
  6922.  
  6923.  
  6924. Routine:  ISize
  6925. ---------------
  6926.  
  6927. Category:            Utility Routine
  6928.  
  6929. Register on entry:   AX- 16-bit value to compute the
  6930.                 output size for.
  6931.  
  6932. Register on return:  AX- Number of print positions
  6933.                 required by this number (including
  6934.                 the minus sign, if necessary).
  6935.  
  6936. Flags affected:      None
  6937.  
  6938. Example of usage:
  6939.              mov     ax, I
  6940.              ISize
  6941.              puti                    ;Prints positions
  6942.                          ;req'd by I.
  6943.  
  6944.  
  6945. Description:         This routine computes the number of print positions
  6946.              required by a 16-bit signed integer value.  ISize computes
  6947.              the minimum number of character positions it takes to print
  6948.              the signed decimal value in the AX register.  If the number
  6949.              is negative, it will include space for the minus sign in
  6950.              the count.
  6951.  
  6952.  
  6953. Include:             stdlib.a or util.a
  6954.  
  6955.  
  6956.  
  6957.  
  6958. Routine:  USize
  6959. ---------------
  6960.  
  6961. Category:            Utility Routine
  6962.  
  6963. Register on entry:   AX- 16 bit value to compute the
  6964.                 output size for
  6965.  
  6966. Register on return:  AX- number of print positions
  6967.              required by this number (including
  6968.              the minus sign, if necessary)
  6969.  
  6970. Flags affected:      None
  6971.  
  6972. Example of usage:
  6973.              mov     ax, I
  6974.              USize
  6975.              puti                    ;prints position
  6976.                          ;required by I
  6977.  
  6978.  
  6979. Description:         This routine computes the number of print positions
  6980.              required by a 16-bit signed integer value.  It also
  6981.              computes the number of print positions required by a
  6982.              16-bit unsigned value.  USize computes the minimum number
  6983.              of character positions it will take to print an unsigned
  6984.              decimal value in the AX register.  If the number is
  6985.              negative, it will include space for the minus sign in the
  6986.              count.
  6987.  
  6988.  
  6989. Include:             stdlib.a or util.a
  6990.  
  6991.  
  6992. Routine:  LSize
  6993. ---------------
  6994.  
  6995. Category:            Utility Routine
  6996.  
  6997. Register on entry:   DX:AX   - 32-bit value to compute the
  6998.                    output size for.
  6999.  
  7000. Register on return:  AX - Number of print positions
  7001.               required by this number (including
  7002.               the minus sign, if necessary).
  7003.  
  7004. Flags affected:      None
  7005.  
  7006. Example of Usage:
  7007.              mov     ax, word ptr L
  7008.              mov     dx, word ptr L+2
  7009.              LSize
  7010.              puti                    ;Prints positions
  7011.                          ;req'd by L.
  7012.  
  7013.  
  7014. Description:         This routine computes the number of print positions
  7015.              required by a 32-bit signed integer value.  LSize computes
  7016.              the minimum number of character positions it will take to
  7017.              print the signed decimal value in the DX:AX registers.  If
  7018.              the number is negative, it will include space for the minus
  7019.              sign in the count.
  7020.  
  7021.  
  7022. Include:             stdlib.a or util.a
  7023.  
  7024.  
  7025.  
  7026. Routine:  ULSize
  7027. ----------------
  7028.  
  7029. Category:             Utility Routine
  7030.  
  7031. Registers on Entry:   DX:AX - 32-bit value to compute the output size for.
  7032.  
  7033. Registers on return:  AX - number of print positions required by this number
  7034.  
  7035. Flags affected:       None
  7036.  
  7037. Example of Usage:
  7038.               mov     ax, word ptr L
  7039.               mov     dx, word ptr L+2
  7040.               ULSize
  7041.               puti                    ; Prints positions req'd by L
  7042.  
  7043.  
  7044. Description:          ULSize computes the minimum number of character
  7045.               positions it will take to print an unsigned decimal
  7046.               value in the DX:AX registers.
  7047.  
  7048.  
  7049. Include:              stdlib.a or util.a
  7050.  
  7051.  
  7052.  
  7053. Routine:  IsAlNum
  7054. -----------------
  7055.  
  7056. Category:             Utility routine
  7057.  
  7058. Register on entry:    AL - character to check.
  7059.  
  7060. Register on return:   None
  7061.  
  7062. Flags affected:       Zero flag - set if character is alphanumeric,
  7063.               clear if not.
  7064.  
  7065.  
  7066. Example of usage :    mov al, char
  7067.               IsAlNum
  7068.               je IsAlNumChar
  7069.  
  7070.  
  7071. Description :         This routine checks the character in the AL register to
  7072.               see if it is in the range A-Z, a-z, or 0-9.  Upon return,
  7073.               you can use the JE instruction to check to see if the
  7074.               character was in this range (or, conversely, you can use
  7075.               JNE to see if it is not in range).
  7076.  
  7077.  
  7078. Include:              stdlib.a or util.a
  7079.  
  7080.  
  7081. Routine:  IsXDigit
  7082. ------------------
  7083.  
  7084. Category:               Utility Routine
  7085.  
  7086. Register on Entry:     AL- character to check
  7087.  
  7088. Registers on Return:    None
  7089.  
  7090. Flags Affected:         Zero flag-  Set if character is a hex digit, clear if not
  7091.  
  7092.  
  7093. Example of Usage:       mov    al, char
  7094.             IsXDigit
  7095.             je     IsXDigitChar
  7096.  
  7097.  
  7098. Description:            This routine checks the character in the AL register to
  7099.             see if it is in the range A-F, a-f, or 0-9.  Upon
  7100.             return, you can use the JE instruction to check to see
  7101.             if the character was in this range (or, conversely,
  7102.             you can use jne to see if it is not in the range).
  7103.  
  7104.  
  7105. Include:                stdlib.a or util.a
  7106.  
  7107.  
  7108. Routine:   IsDigit
  7109. ------------------
  7110.  
  7111. Category:            Utility Routine
  7112.  
  7113. Register on entry:   AL- Character to check
  7114.  
  7115. Register on return:  None
  7116.  
  7117. Flags affected:         Zero flag- set if character is numeric, clear if not.
  7118.  
  7119. Example of Usage:    mov   al, char
  7120.              IsDigit
  7121.              je  IsDecChar
  7122.  
  7123.  
  7124. Description:         This routine checks the character in the AL register to
  7125.              see if it is in the range 0-9.  Upon return, you can use
  7126.              the JE instruction to check to see if the character was
  7127.              in the range (or, conversely, you can use JNE to see if it
  7128.              is not in the range).
  7129.  
  7130.  
  7131. Include:             stdlib.a or util.a
  7132.  
  7133.  
  7134. Routine:   IsAlpha
  7135. ------------------
  7136.  
  7137. Category:            Utility Routine
  7138.  
  7139. Register on entry:   AL- Character to check
  7140.  
  7141. Register on return:  None
  7142.  
  7143. Flags affected:         Zero flag- set if character is alphabetic, clear if not.
  7144.  
  7145. Example of Usage:    mov   al, char
  7146.              IsAlpha
  7147.              je   IsAlChar
  7148.  
  7149.  
  7150. Description:         This routine checks the character in the AL register to
  7151.              see if it is in the range A-Z or a-z.  Upon return, you
  7152.              can use the JE instruction to check to see if the character
  7153.              was in the range (or, conversely, you can use JNE to see
  7154.              if it is not in the range).
  7155.  
  7156. Include:             stdlib.a or util.a
  7157.  
  7158.  
  7159.  
  7160.  
  7161. Routine: IsLower
  7162. ----------------
  7163.  
  7164. Category:             Utility Routine
  7165.  
  7166. Registers on Entry:   AL- character to test
  7167.  
  7168. Registers on Return:  None
  7169.  
  7170.  
  7171. Flags Affected:       Zero = 1 if character is a lower case alphabetic character
  7172.               Zero = 0 if character is not a lower case alphabetic
  7173.               character
  7174.  
  7175. Example of Usage:     mov  AL, char        ; put char in AL
  7176.               IsLower              ; is char lower a-z?
  7177.               je  IsLowerChar      ; if yes, jump to IsLowerChar
  7178.  
  7179.  
  7180. Description:          This routine checks the character in the AL register to
  7181.               see if it is in the range a-z.  Upon return, you can use
  7182.               the JE instruction to check and see if the character was
  7183.               in this range (or you can use JNE to check and see if
  7184.               the character was not in this range).  This procedure is
  7185.               implemented as a macro for high performance.
  7186.  
  7187.  
  7188. Include:              stdlib.a or util.a
  7189.  
  7190.  
  7191. Routine:  IsUpper
  7192. -----------------
  7193.  
  7194. Category:             Utility Routine
  7195.  
  7196. Registers on Entry:   AL- character to check
  7197.  
  7198. Registers on Return:  None
  7199.  
  7200. Flags Affected:       Zero flag - set if character is uppercase alpha, clear
  7201.                   if not.
  7202.  
  7203.  
  7204. Example of Usage:     mov al, char
  7205.               IsUpper
  7206.               je IsUpperChar
  7207.  
  7208.  
  7209. Description:          This routine checks the character in the AL register to
  7210.               see if it is in the ranger A-Z.  Upon return, you can use
  7211.               the JE instruction to check to see if it not in the
  7212.               range).  It uses macro implementation for high performance.
  7213.  
  7214.  
  7215. Include:              stdlib.a or util.a
  7216.  
  7217. Linked list manipulation routines
  7218. =================================
  7219.  
  7220. These routines manipulate items in a linked list.  Internally the system
  7221. represents the data as a doubly linked list, although your program should
  7222. not rely on the internal structure of the data structure.
  7223.  
  7224. There are two structures of interest defined in the LISTS.A file: LIST
  7225. and NODE.  Use variables of type LIST to create brand new lists.  Use
  7226. variables of type NODE to hold the entries in the list.
  7227.  
  7228. These structures take the following form:
  7229.  
  7230. List        struc
  7231. Size        dw    ?        ;Size, in bytes, of a node in the list
  7232. Head        dd    0        ;Ptr to start of list
  7233. Tail        dd    0        ;Ptr to end of list
  7234. Current        dd    0        ;Pointer to current node
  7235. List        ends
  7236.  
  7237. Node        struc
  7238. Next        dd    ?        ;Ptr to next node in list
  7239. Prev        dd    ?        ;Ptr to prev node in list
  7240. NodeData    db    ??        ;Data immediately follows Prev
  7241. Node        ends
  7242.  
  7243.  
  7244. There are two ways to create a new list: statically or dynamically.
  7245. Consider static allocation first.  In this case, you create a list variable
  7246. by declaring an object of type LIST in a data segment, e.g.,
  7247.  
  7248. MyList        list    <25>
  7249.  
  7250. You *must* supply the size (in bytes) of a node in the list.  Note that the
  7251. size should *not* include the eight bytes required for the next and prev
  7252. pointers.  This allows you to change the internal structure of the list
  7253. (e.g., to a singly linked list) without having to change other code.  You
  7254. can easily compute this as follows:
  7255.  
  7256. MyList        list    <(sizeof MyNode) - (sizeof Node)>
  7257.  
  7258. When you declare lists in this fashion, the definition automatically
  7259. initializes the list to an empty list.
  7260.  
  7261. You can also create a list dynamically by calling the CreateList routine.
  7262. To CreateList you must pass the size of a Node (not including the pointers)
  7263. in the CX register.  It allocates storage for the list variable on the
  7264. heap and returns a pointer to this new (empty) list in es:di.
  7265.  
  7266.         mov    cx, (sizeof MyNode) - (sizeof Node)
  7267.         CreateList
  7268.         mov    word ptr MyListPtr, di
  7269.         mov    word ptr MyListPtr+2, es
  7270.  
  7271.  
  7272. To create nodes for your list, you should "overload" the NODE definition
  7273. appearing the in LISTS.A file.  This works best under MASM 6.0 and TASM 3.0,
  7274. which support object-oriented programming, though it isn't that difficult to
  7275. accomplish with other assemblers.  A mechanism compatible with *all*
  7276. assemblers follows:
  7277.  
  7278. To create a brand new node is easy,  just do the following:
  7279.  
  7280. MyNode        struc
  7281.         db    (size Node) dup (0)     ;Inherit all fields from NODE.
  7282. Field1        db    ?            ;User-supplied fields for this
  7283. Field2        dw    ?            ; particular node type.
  7284. Field3        dd    ?            ;  "    "     "    "
  7285. Field4        real4    3.14159            ;  "    "     "    "
  7286. MyNode        ends
  7287.  
  7288. Note that the NODE fields must appear *first* in the data structure.
  7289. The list manipulation routines assume that the list pointers in NODE appear
  7290. at the beginning of the structure.
  7291.  
  7292. The CurrentNode field of the list data structure points at a "current" node
  7293. in the list.  The current node is the last node operated on in the case of
  7294. insert, append, peek, etc.  In the event a node is removed, the current node
  7295. will be the next node after the node removed.  In general, the current node
  7296. can be thought of as a "cursor" which wanders through the list according to
  7297. the operations occuring.  Since most list operations occur on the next node
  7298. in a list, keeping the CurrentNode field updated speeds up access to the
  7299. list.
  7300.  
  7301. You can use the following routines to implement the corresponding data
  7302. structures (which can all be implemented using lists):
  7303.  
  7304. FIFO Queues:
  7305.  
  7306. AppendLastm, AppendLast, Remove1st, and Peek1st (technically, using Peek1st
  7307. is cheating, but so what).
  7308.  
  7309.  
  7310.  
  7311. Deques (double ended queues):
  7312.  
  7313. All the FIFO routines plus InsertFirstm, InsertFirst, RemoveLast, and
  7314. PeekLast (PeekLast is cheating too).
  7315.  
  7316.  
  7317. Lists:
  7318.  
  7319. All of the above plus InsertCur, InsertmCur, AppendCur, AppendmCur,
  7320. RemoveCur, Insert, Insertm, Append, Appendm, Remove, SetCur, NextNode,
  7321. and PrevNode.
  7322.  
  7323. For those who care about such things, the UCR Standard Library implements
  7324. the list data structure using a doubly linked list.  However, it is a
  7325. true generic (encapsulated) data type and your code needed be at all
  7326. concerned about the internal structure.  Furthermore, assuming you treat
  7327. it like an encapsulated data structure, you can modify the internal list
  7328. structure and not break any programs which use the list data types.
  7329.  
  7330.  
  7331.  
  7332.  
  7333.  
  7334. Routine:  CreateList
  7335. --------------------
  7336.  
  7337. Author:              Randall Hyde
  7338.  
  7339. Category:             List Manipulation
  7340.  
  7341. Registers on entry:       CX-    Size of data (in bytes) to store at each node
  7342.  
  7343. Registers on return:      ES:DI-    Pointer to new list variable on heap
  7344.  
  7345. Flags affected:           Carry set if CreateList cannot allocate sufficient
  7346.             storage on the heap for the list variable.
  7347.  
  7348. Example of Usage:
  7349.             mov    cx, (sizeof MyNode) - (sizeof Node)
  7350.             CreateList
  7351.             jc    ListError
  7352.             mov    word ptr ListVarPtr, di
  7353.             mov    word ptr ListVarPtr+2, es
  7354.  
  7355. Description:
  7356.  
  7357. CreateList allocates storage for a list variable on the head and initializes
  7358. that variable to the empty list.  It also sets up the size field of the
  7359. list variable based on the value passed in the CX register.  It returns
  7360. a pointer to the newly created list in the ES:DI registers.
  7361.  
  7362. This routine initializes the CurrentNode field to NIL.  Any node inserted
  7363. before or after the current node will be inserted as the first node in this
  7364. case.
  7365.  
  7366. Include:    lists.a or stdlib.a
  7367.  
  7368.  
  7369.  
  7370. Routine:  AppendLast (m)
  7371. ------------------------
  7372.  
  7373. Author:              Randall Hyde
  7374.  
  7375. Category:             List Manipulation
  7376.  
  7377. Registers on entry:       DX:SI-    Pointer to node to add to list (AppendLast)
  7378.             DX:SI-    Pointer to block of data (sans list stuff)
  7379.                 to add to end of list (AppendLastm)
  7380.             ES:DI-    Pointer to list.
  7381.  
  7382. Registers on return:      ES:DI-    Pointer to list.
  7383.  
  7384. Flags affected:           Carry set if AppendLastm cannot allocate sufficient
  7385.             storage on the heap for the list variable.
  7386.  
  7387. Examples of Usage:
  7388.  
  7389. ; Append data statically declared as ANode to the end of the list pointed at
  7390. ; by the list variable "ListVar".
  7391.  
  7392.             ldxi    ANode
  7393.             les    di, ListVar
  7394.             AppendLast
  7395.  
  7396. ; Create a node from the data at address "MyData".  Build the node on the
  7397. ; heap and append this node to the end of the list pointed at by ListVar.
  7398.  
  7399.             ldxi    MyData
  7400.             les    di, ListVar
  7401.             AppendLastm
  7402.             jc    BadListError
  7403.  
  7404. Description:
  7405.  
  7406. AppendLast and AppendLastm add a node to the end of a list.  AppendLast works
  7407. with whole nodes.  It is useful, for example when moving a node from one
  7408. list to another or when dealing with nodes that were created statically in
  7409. the program.  It requires nodes properly declared using the NODE data type
  7410. in the LIST.A include file.
  7411.  
  7412. AppendLastm builds a new node on the heap and appends this node to the end
  7413. of the specified list.  The difference between AppendLastm and AppendLast is
  7414. that AppendLastm does not require a predefined node.  Instead, DX:SI points
  7415. at the data for the node (the number of bytes is specified by the ListSize
  7416. field of the LIST data type).  AppendLastm allocates memory, copies the data
  7417. from DX:SI to the data field of the new node, and then links in the new node
  7418. to the specified list.
  7419.  
  7420. The new node added to the list becomes the CurrentNode.
  7421.  
  7422. Include:    stdlib.a or lists.a
  7423.  
  7424.  
  7425.  
  7426. Routine:  Remove1st
  7427. -------------------
  7428.  
  7429. Author:                  Randall Hyde
  7430.  
  7431. Category:                 List Manipulation
  7432.  
  7433. Registers on entry:       ES:DI-    Pointer to list variable.
  7434.  
  7435. Registers on return:    DX:SI-    Pointer to node removed from the front of
  7436.                 the list (NIL if nothing in list).
  7437.  
  7438. Flags affected:           Carry set if the list was empty.
  7439.  
  7440. Examples of Usage:
  7441.  
  7442. ; The following loop removes all the items from a list and processes each
  7443. ; item.
  7444.  
  7445. DoAllOfList:        les    di, MyList
  7446.             Remove1st
  7447.             jc    DidItAll
  7448.             <manipulate this item>
  7449.             jmp    DoAllOfList
  7450. DidItAll:
  7451.  
  7452.  
  7453. Description:
  7454.  
  7455. Remove1st removes the first item from a list and returns a pointer to that
  7456. item in DX:SI.  If the list was empty, then it returns a NIL pointer in
  7457. DX:SI and returns with the carry flag set.
  7458.  
  7459. Note that you can use the AppendLast(m) and Remove1st routines to implement
  7460. and manipulate a FIFO queue data structure.  Peek1st is another useful
  7461. routine which returns the first item on a list without removing it from
  7462. the list.
  7463.  
  7464. The second node in the list (the one after the node just removed) becomes
  7465. the new CurrentNode.  If there are no additional nodes in the list, the
  7466. CurrentNode variable gets set to NIL.
  7467.  
  7468. Include:    stdlib.a or lists.a
  7469.  
  7470.  
  7471.  
  7472.  
  7473. Routine:  Peek1st
  7474. -----------------
  7475.  
  7476. Author:                  Randall Hyde
  7477.  
  7478. Category:                 List Manipulation
  7479.  
  7480. Registers on entry:       ES:DI-    Pointer to list variable.
  7481.  
  7482. Registers on return:    DX:SI-    Pointer to node at the beginning of
  7483.                 the list (NIL if nothing in list).
  7484.  
  7485. Flags affected:           Carry set if the list was empty.
  7486.  
  7487. Examples of Usage:
  7488.  
  7489.             les    di, MyList
  7490.             Peek1st
  7491.             jc    NothingThere
  7492.  
  7493. Description:
  7494.  
  7495. Peek1st is similar to Remove1st in that it returns a pointer to the first
  7496. item in a list (NIL if the list is empty).  However, it does not remove the
  7497. item from the list.  This is useful for performing a "non-destructive" read
  7498. of the first item in a FIFO queue.
  7499.  
  7500. This routine sets the CurrentNode field to the first node in the list.
  7501.  
  7502. Include:    stdlib.a or lists.a
  7503.  
  7504.  
  7505.  
  7506. Routine:  Insert1st (m)
  7507. -----------------------
  7508.  
  7509. Author:              Randall Hyde
  7510.  
  7511. Category:             List Manipulation
  7512.  
  7513. Registers on entry:       DX:SI-    Pointer to node to add to list (Insert1st)
  7514.             DX:SI-    Pointer to block of data (sans list stuff)
  7515.                 to add to end of list (Insert1stm)
  7516.             ES:DI-    Pointer to list.
  7517.  
  7518. Registers on return:      ES:DI-    Pointer to list.
  7519.  
  7520. Flags affected:           Carry set if Insertm cannot allocate sufficient
  7521.             storage on the heap for the list variable.
  7522.  
  7523. Examples of Usage:
  7524.  
  7525. ; Insert data statically declared as ANode to the beginning of the list
  7526. ; pointed at by the list variable "ListVar".
  7527.  
  7528.             ldxi    ANode
  7529.             les    di, ListVar
  7530.             Insert1st
  7531.  
  7532. ; Create a node from the data at address "MyData".  Build the node on the
  7533. ; heap and insert this node to the beginning of the list pointed at by
  7534. ; ListVar.
  7535.  
  7536.             ldxi    MyData
  7537.             les    di, ListVar
  7538.             Insert1stm
  7539.             jc    BadListError
  7540.  
  7541. Description:
  7542.  
  7543. Insert1st and Insert1stm add a node to the beginning of a list.  Insert1st
  7544. works with whole nodes.  It is useful, for example when moving a node from one
  7545. list to another or when dealing with nodes that were created statically in
  7546. the program.  It requires nodes properly declared using the NODE data type
  7547. in the LISTS.A include file.
  7548.  
  7549. Insert1stm builds a new node on the heap and inserts this node to the start
  7550. of the specified list.  The difference between Insert1stm and Insert1st is
  7551. that Insert1stm does not require a predefined node.  Instead, DX:SI points
  7552. at the data for the node (the number of bytes is specified by the ListSize
  7553. field of the LIST data type).  Insert1stm allocates memory, copies the data
  7554. from DX:SI to the data field of the new node, and then links in the new node
  7555. to the specified list.
  7556.  
  7557. Note that Insert1st/Insert1stm can be used to create Deque data structures.
  7558.  
  7559. The newly inserted node becomes the CurrentNode in the list.
  7560.  
  7561. Include:    stdlib.a or lists.a
  7562.  
  7563.  
  7564.  
  7565. Routine:  RemoveLast
  7566. --------------------
  7567.  
  7568. Author:                  Randall Hyde
  7569.  
  7570. Category:                 List Manipulation
  7571.  
  7572. Registers on entry:       ES:DI-    Pointer to list variable.
  7573.  
  7574. Registers on return:    DX:SI-    Pointer to node removed from the end of
  7575.                 the list (NIL if nothing in list).
  7576.  
  7577. Flags affected:           Carry set if the list was empty.
  7578.  
  7579. Examples of Usage:
  7580.  
  7581. ; The following loop removes all the items from a list and processes each
  7582. ; item.
  7583.  
  7584. DoAllOfList:        les    di, MyList
  7585.             RemoveLast
  7586.             jc    DidItAll
  7587.             <manipulate this item>
  7588.             jmp    DoAllOfList
  7589. DidItAll:
  7590.  
  7591.  
  7592. Description:
  7593.  
  7594. RemoveLast removes the last item from a list and returns a pointer to that
  7595. item in DX:SI.  If the list was empty, then it returns a NIL pointer in
  7596. DX:SI and returns with the carry flag set.
  7597.  
  7598. Note that you can use the Insert1st(m) and RemoveLast routines to implement
  7599. and manipulate a DEQUE queue data structure (along with the FIFO routines:
  7600. AppendLast(m), Rmv1st, and Peek1st).  PeekLast is another useful
  7601. routine which returns the last item on a list without removing it from
  7602. the list.
  7603.  
  7604. The last node in the list (the one before the node just removed) becomes the
  7605. new CurrentNode in the list.  If the list is empty, CurrentNode gets set to
  7606. NIL.
  7607.  
  7608. Include:    stdlib.a or lists.a
  7609.  
  7610.  
  7611.  
  7612.  
  7613. Routine:  PeekLast
  7614. ------------------
  7615.  
  7616. Author:                  Randall Hyde
  7617.  
  7618. Category:                 List Manipulation
  7619.  
  7620. Registers on entry:       ES:DI-    Pointer to list variable.
  7621.  
  7622. Registers on return:    DX:SI-    Pointer to node at the end of
  7623.                 the list (NIL if nothing in list).
  7624.  
  7625. Flags affected:           Carry set if the list was empty.
  7626.  
  7627. Examples of Usage:
  7628.  
  7629.             les    di, MyList
  7630.             PeekLast
  7631.             jc    NothingThere
  7632.  
  7633. Description:
  7634.  
  7635. PeekLast is just like Peek1st except it looks at the last node on the list
  7636. rather than the first.  It does the same job as RemoveLast except it does
  7637. not remove the node from the list.  Great for implementing Deques.
  7638.  
  7639. This routine also sets the CurrentNode field to point at the last node in
  7640. the list.
  7641.  
  7642. Include:    stdlib.a or lists.a
  7643.  
  7644.  
  7645.  
  7646.  
  7647. Routine:  InsertCur
  7648. -------------------
  7649.  
  7650. Author:                  Randall Hyde
  7651.  
  7652. Category:                 List Manipulation
  7653.  
  7654. Registers on entry:       ES:DI-    Pointer to list.
  7655.             DX:SI-    Pointer to node to insert
  7656.  
  7657. Examples of Usage:
  7658.  
  7659.             les    di, MyList
  7660.             ldxi    NewNode
  7661.             InsertCur
  7662.  
  7663. Description:
  7664.  
  7665. InsertCur inserts the node pointed at by DX:SI before the "current" node in
  7666. the list.  The current node is the last one operated on by the software.
  7667.  
  7668. The newly inserted node becomes the CurrentNode in the list.
  7669.  
  7670. Include:    stdlib.a or lists.a
  7671.  
  7672.  
  7673.  
  7674.  
  7675. Routine:  InsertmCur
  7676. --------------------
  7677.  
  7678. Author:                  Randall Hyde
  7679.  
  7680. Category:                 List Manipulation
  7681.  
  7682. Registers on entry:       ES:DI-    Pointer to list.
  7683.             DX:SI-    Pointer to data for node to insert
  7684.  
  7685. Flags on exit:        Carry flag is set if malloc error occurs.
  7686.  
  7687. Examples of Usage:
  7688.  
  7689.             les    di, MyList
  7690.             ldxi    DataBlock
  7691.             InsertmCur
  7692.             jc    Error
  7693.  
  7694. Description:
  7695.  
  7696. InsertmCur builds a new node on the heap (using the block of data pointed at
  7697. by DX:SI and the size of a node in the size field of the list variable) and
  7698. then inserts the new node before the "current" node in the list.  The current
  7699. node is the last one operated on by the software.
  7700.  
  7701. This code treats the newly inserted node as the current node.
  7702.  
  7703. Include:    stdlib.a or lists.a
  7704.  
  7705.  
  7706.  
  7707. Routine:  AppendCur
  7708. -------------------
  7709.  
  7710. Author:                  Randall Hyde
  7711.  
  7712. Category:                 List Manipulation
  7713.  
  7714. Registers on entry:       ES:DI-    Pointer to list.
  7715.             DX:SI-    Pointer to node to append
  7716.  
  7717. Examples of Usage:
  7718.  
  7719.             les    di, MyList
  7720.             ldxi    NewNode
  7721.             AppendCur
  7722.  
  7723. Description:
  7724.  
  7725. AppendCur inserts the node pointed at by DX:SI after the "current" node in
  7726. the list.  The current node is the last one operated on by the software.
  7727.  
  7728. The newly inserted node becomes the CurrentNode in the list.
  7729.  
  7730. Include:    stdlib.a or lists.a
  7731.  
  7732.  
  7733.  
  7734.  
  7735. Routine:  AppendmCur
  7736. --------------------
  7737.  
  7738. Author:                  Randall Hyde
  7739.  
  7740. Category:                 List Manipulation
  7741.  
  7742. Registers on entry:       ES:DI-    Pointer to list.
  7743.             DX:SI-    Pointer to data for node to insert.
  7744.  
  7745. Flags on exit:        Carry flag is set if malloc error occurs.
  7746.  
  7747. Examples of Usage:
  7748.  
  7749.             les    di, MyList
  7750.             ldxi    DataBlock
  7751.             AppendmCur
  7752.             jc    MallocError
  7753.  
  7754. Description:
  7755.  
  7756. AppendmCur builds a new node on the heap (using the block of data pointed at
  7757. by DX:SI and the size of a node in the size field of the list variable) and
  7758. then inserts the new node after the "current" node in the list.  The current
  7759. node is the last one operated on by the software.
  7760.  
  7761. This code treats the newly inserted node as the current node.
  7762.  
  7763. Include:    stdlib.a or lists.a
  7764.  
  7765.  
  7766.  
  7767. Routine:  RemoveCur
  7768. -------------------
  7769.  
  7770. Author:                  Randall Hyde
  7771.  
  7772. Category:                 List Manipulation
  7773.  
  7774. Registers on entry:       ES:DI-    Pointer to list.
  7775.  
  7776. Registers on exit:    DX:SI-    Points at node removed from list (NIL if
  7777.                 no such node).
  7778.  
  7779. Flags on return:    Carry set if the list was empty.
  7780.  
  7781. Examples of Usage:
  7782.  
  7783.             les    di, MyList
  7784.             RemoveCur
  7785.             jc    EmptyList
  7786.  
  7787. Description:
  7788.  
  7789. RemoveCur removes the current node (pointed at by CurrentNode) from the list
  7790. and returns a pointer to this node in DX:SI.  If the list was empty, RemoveCur
  7791. returns NIL in DX:SI and sets the carry flag.
  7792.  
  7793. This routine modifies CurrentNode so that it points at the next item in the
  7794. list (the node normally following the current node).  If there is no such
  7795. node (i.e., CurrentNode pointed at the last node in the list upon calling
  7796. RemoveCur) then this routine stores the value of the *previous* node into
  7797. CurrentNode.  If you use this routine to delete the last node in the list,
  7798. it sets CurrentNode to NIL before leaving.
  7799.  
  7800. Include:    stdlib.a or lists.a
  7801.  
  7802.  
  7803.  
  7804. Routine:  PeekCur
  7805. -----------------
  7806.  
  7807. Author:                  Randall Hyde
  7808.  
  7809. Category:                 List Manipulation
  7810.  
  7811. Registers on entry:       ES:DI-    Pointer to list.
  7812.  
  7813. Registers on exit:    DX:SI-    Points at the current node (i.e., contains
  7814.                 a copy of CurrentNode), NIL if the list
  7815.                 is empty.
  7816.  
  7817. Flags on return:    Carry set if the list was empty.
  7818.  
  7819. Examples of Usage:
  7820.  
  7821.             les    di, MyList
  7822.             PeekCur
  7823.             jc    EmptyList
  7824.  
  7825. Description:
  7826.  
  7827. PeekCur simply returns CurrentNode in DX:SI (assuming the list is not empty).
  7828. If the list is empty, it returns the carry flag set and NIL in DX:SI.
  7829. It does not affect the value of CurrentNode.
  7830.  
  7831. Include:    stdlib.a or lists.a
  7832.  
  7833.  
  7834.  
  7835. Routine:  SetCur
  7836. ----------------
  7837.  
  7838. Author:                  Randall Hyde
  7839.  
  7840. Category:                 List Manipulation
  7841.  
  7842. Registers on entry:       ES:DI-    Pointer to list.
  7843.             CX-    Node number of new current node.
  7844.  
  7845. Registers on exit:    DX:SI-    Returned pointing at selected node.
  7846.                 NIL if the list is empty.  Points at the
  7847.                 last node in the list if the value in CX
  7848.                 is greater than the number of nodes in the
  7849.                 list.
  7850.  
  7851. Flags on return:    Carry set if the list was empty.
  7852.  
  7853. Examples of Usage:
  7854.  
  7855.             les    di, MyList
  7856.             mov    cx, NodeNum
  7857.             SetCur
  7858.             jc    EmptyList
  7859.  
  7860. Description:
  7861.  
  7862. SetCur locates the specified node in the list and sets CurrentNode to the
  7863. address of that node. It also returns a pointer to that node in DX:SI.
  7864. If CX is greater than the number of nodes in the list (or zero) then
  7865. SetCur sets CurrentNode to the last node in the list.  If the list is
  7866. empty, SetCur returns NIL in DX:SI and returns with the carry flag set.
  7867.  
  7868. Include:    stdlib.a or lists.a
  7869.  
  7870.  
  7871.  
  7872. Routine:  NextNode
  7873. ------------------
  7874.  
  7875. Author:                  Randall Hyde
  7876.  
  7877. Category:                 List Manipulation
  7878.  
  7879. Registers on entry:       ES:DI-    Pointer to list.
  7880.  
  7881. Registers on exit:    DX:SI-    Returned pointing at selected node.
  7882.                 NIL if the list is empty.  Points at the
  7883.                 last node in the list if the current node
  7884.                 was the last node in the list
  7885.  
  7886. Flags on return:    Carry set if the current node was the last node
  7887.             or the list was empty.
  7888.  
  7889. Examples of Usage:
  7890.  
  7891.             les    di, MyList
  7892.             NextNode
  7893.             jc    EmptyOrEnd
  7894.  
  7895. Description:
  7896.  
  7897. NextNode modifies the CurrentNode pointer so that it points to the next
  7898. node in the list, if there is one. It also returns a pointer to that node
  7899. in DX:SI.  If the list is empty, or CurrentNode points at the last node
  7900. in the list, NextNode returns with the carry flag set.
  7901.  
  7902. Include:    stdlib.a or lists.a
  7903.  
  7904.  
  7905.  
  7906. Routine:  PrevNode
  7907. ------------------
  7908.  
  7909. Author:                  Randall Hyde
  7910.  
  7911. Category:                 List Manipulation
  7912.  
  7913. Registers on entry:       ES:DI-    Pointer to list.
  7914.  
  7915. Registers on exit:    DX:SI-    Returned pointing at selected node.
  7916.                 NIL if the list is empty.  Points at the
  7917.                 1st node in the list if the current node
  7918.                 was the 1st node in the list
  7919.  
  7920. Flags on return:    Carry set if the current node was the 1st node
  7921.             or the list was empty.
  7922.  
  7923. Examples of Usage:
  7924.  
  7925.             les    di, MyList
  7926.             PrevNode
  7927.             jc    EmptyOr1st
  7928.  
  7929. Description:
  7930.  
  7931. PrevNode modifies the CurrentNode pointer so that it points to the previous
  7932. node in the list, if there is one. It also returns a pointer to that node
  7933. in DX:SI.  If the list is empty, or CurrentNode points at the 1st node
  7934. in the list, PrevNode returns with the carry flag set.
  7935.  
  7936. Include:    stdlib.a or lists.a
  7937.  
  7938.  
  7939.  
  7940. Routine:  Insert (m)
  7941. --------------------
  7942.  
  7943. Author:                  Randall Hyde
  7944.  
  7945. Category:                 List Manipulation
  7946.  
  7947. Registers on entry:       ES:DI-    Pointer to list.
  7948.             DX:SI-    Address of node to insert (Insert)
  7949.             DX:SI-    Pointer to data block to create node from
  7950.                 (Insertm).
  7951.             CX-    Number of node to insert DX:SI in front of;
  7952.                 Note that the list is one-based.  That is,
  7953.                 the number of the first node in the list is
  7954.                 one.  Zero corresponds to the last node in
  7955.                 the list.
  7956.  
  7957.  
  7958. Flags on return:    Carry set if malloc error occurs (Insertm only).
  7959.  
  7960. Examples of Usage:
  7961.  
  7962.             les    di, MyList
  7963.             ldxi    NewNode
  7964.             mov    cx, 5
  7965.             Insert            ;Inserts before Node #5.
  7966.  
  7967. ; The following example builds a new node on the heap from the data at
  7968. ; location "RawData" and inserts this before node #5 in MyList.
  7969.  
  7970.             les    di, MyList
  7971.             ldxi    RawData
  7972.             mov    cx, 5
  7973.             Insertm
  7974.             jc    MallocError
  7975.  
  7976. Description:
  7977.  
  7978. Insert(m) inserts a new node before a specified node in the list.  The node to
  7979. insert in front of is specified by the value in the CX register.  The first
  7980. node in the list is node #1, the second is node #2, etc.  If the value in
  7981. CX is greater than the number of nodes in the list (in particular, if CX
  7982. contains zero, which gets treated like 65,536) then Insert(m) appends the
  7983. new node to the end of the list.
  7984.  
  7985. Insertm allocates a new node on the heap (DX:SI points at the data fields
  7986. for the node).  If a malloc error occurs, Insertm returns the carry flag
  7987. set.
  7988.  
  7989. CurrentNode gets set to the newly inserted node.
  7990.  
  7991. Include:    stdlib.a or lists.a
  7992.  
  7993.  
  7994.  
  7995. Routine:  Append (m)
  7996. --------------------
  7997.  
  7998. Author:                  Randall Hyde
  7999.  
  8000. Category:                 List Manipulation
  8001.  
  8002. Registers on entry:       ES:DI-    Pointer to list.
  8003.             DX:SI-    Address of node to insert (Append)
  8004.             DX:SI-    Pointer to data block to create node from
  8005.                 (Appendm).
  8006.             CX-    Number of node to insert DX:SI after;
  8007.                 Note that the list is one-based.  That is,
  8008.                 the number of the first node in the list is
  8009.                 one.  Zero corresponds to the last node in
  8010.                 the list.
  8011.  
  8012.  
  8013. Flags on return:    Carry set if malloc error occurs (Appendm only).
  8014.  
  8015. Examples of Usage:
  8016.  
  8017.             les    di, MyList
  8018.             ldxi    NewNode
  8019.             mov    cx, 5
  8020.             Append            ;Inserts after Node #5.
  8021.  
  8022. ; The following example builds a new node on the heap from the data at
  8023. ; location "RawData" and inserts this after node #5 in MyList.
  8024.  
  8025.             les    di, MyList
  8026.             ldxi    RawData
  8027.             mov    cx, 5
  8028.             Appendm
  8029.             jc    MallocError
  8030.  
  8031. Description:
  8032.  
  8033. Append(m) inserts a new node after a specified node in the list.  The node to
  8034. insert in front of is specified by the value in the CX register.  The first
  8035. node in the list is node #1, the second is node #2, etc.  If the value in
  8036. CX is greater than the number of nodes in the list (in particular, if CX
  8037. contains zero, which gets treated like 65,536) then Insert(m) appends the
  8038. new node to the end of the list.
  8039.  
  8040. Appendm allocates a new node on the heap (DX:SI points at the data fields
  8041. for the node).  If a malloc error occurs, Appendm returns the carry flag
  8042. set.
  8043.  
  8044. CurrentNode gets set to the newly inserted node.
  8045.  
  8046. Include:    stdlib.a or lists.a
  8047.  
  8048.  
  8049.  
  8050.  
  8051. Routine:  Remove
  8052. ----------------
  8053.  
  8054. Author:                  Randall Hyde
  8055.  
  8056. Category:                 List Manipulation
  8057.  
  8058. Registers on entry:       ES:DI-    Pointer to list.
  8059.             CX-    # of node to delete from list.
  8060.  
  8061. Registers on exit:    DX:SI-    Points at node removed from list (NIL if
  8062.                 no such node).
  8063.  
  8064. Flags on return:    Carry set if the list was empty.
  8065.  
  8066. Examples of Usage:
  8067.  
  8068.             les    di, MyList
  8069.             mov    cx, NodeNumbr
  8070.             Remove
  8071.             jc    EmptyList
  8072.  
  8073. Description:
  8074.  
  8075. Remove removes the specified node (given by CX) from the list
  8076. and returns a pointer to this node in DX:SI.  If the list was empty, Remove
  8077. returns NIL in DX:SI and sets the carry flag.
  8078.  
  8079. This routine modifies CurrentNode so that it points at the next item in the
  8080. list (the node normally following the current node).  If there is no such
  8081. node (i.e., CurrentNode pointed at the last node in the list upon calling
  8082. Remove) then this routine stores the value of the *previous* node into
  8083. CurrentNode.  If you use this routine to delete the last node in the list,
  8084. it sets CurrentNode to NIL before leaving.
  8085.  
  8086. Include:    stdlib.a or lists.a
  8087.  
  8088.  
  8089.               IBM/L 1.0
  8090. (Instruction Benchmarking Language)
  8091.  
  8092. This program lets you time sequences of instructions to see how much time
  8093. they *really* take to execute.  The cycle timings in most 80x86 assembly
  8094. language books are horribly inaccurate as they assume the absolute best
  8095. case.  IBM/L lets you try out some instruction sequences and see how
  8096. much time they really take.
  8097.  
  8098. IBM/L uses the system 1/18th second clock and measures most executions
  8099. in terms of clock ticks.  Therefore, it would be totally useless for
  8100. measure the speed of a single instruction (since all instructions execute
  8101. in *much* less than 1/18th second).  IBM/L works by repeatedly executing
  8102. a code sequence thousands (or millions) of times and measuring that amount
  8103. of time.  IBM/L automatically subtracts away the loop overhead time.
  8104.  
  8105. IBM/L is a very crude program, something like the "Zen Timer" (from
  8106. Michael Abrash's book "Zen of Assembly") would be more appropriate
  8107. if you need absolutely accurate timings.  The intent of this program
  8108. is to give you a good feeling for which instructions are faster than
  8109. others.
  8110.  
  8111. IBM/L programs begin with an optional data section. The data section begins
  8112. with a line containing "#DATA" and ends with a line containing "#ENDDATA".
  8113. All lines between these two lines are copied to an output assembly language
  8114. program inside the DSEG data segment.  Typically you would put global
  8115. variables into the program at this point.  As a general rule, you should not
  8116. use names which begin with a period.  IBM/L prefaces all its names with a
  8117. period and you could run into a conflict were you to use such names.
  8118. Note:if you are using MASM 6.0 or later, you must select the option which
  8119. allows identifiers to begin with a period.  MASM 5.1 and earlier do not
  8120. have a problem with such identifiers.
  8121.  
  8122. Example of a data section:
  8123.  
  8124. #DATA
  8125. I    dw    ?
  8126. J    dw    ?
  8127. K    dd    ?
  8128. ch    db    ?
  8129. ch2    db    ?
  8130. #ENDDATA
  8131.  
  8132. These lines would be copied to a data segment in the created program.
  8133. Note that these names would be available to *all* code sequences you
  8134. place in the following code sections.
  8135.  
  8136.  
  8137. Following the data section are one or more code sections.  A code section
  8138. consists of optional #REPETITION and #UNRAVEL statements followed by the
  8139. actual #CODE / #ENDCODE sections.
  8140.  
  8141. The #REPETITION statement takes the following form:
  8142.  
  8143.     #REPETITION value1, value2
  8144.  
  8145. (The "#" must be in column one).  "value1" and "value2" must be 16-bit integer
  8146. constants (less than or equal to 65,535).
  8147.  
  8148. This statement instructs IBM/L to generate a loop which repeats the following
  8149. code segment (value1 * value2) times.  I used two values so I could use 16-bit
  8150. arithmetic (easy to perform in C/FLEX/BISON).  If you do not specify any
  8151. repetitions at all, the default is value1=65535 and value2=5.  Once you set
  8152. a repetitions value, that value remains in effect for all following code
  8153. sequences until you explicitly change it again.
  8154.  
  8155. In general, the bigger the value you choose, the more accurate the timing will
  8156. be.  However, as you choose larger and larger values for the repetitions, the
  8157. program code segments will take longer and longer to execute.  Remember,
  8158. the generated assembly language program will repeat the code seqences in a
  8159. loop the specified (value1*value2) number of times.  Short, simple, instruction
  8160. sequences will execute much faster than long, complex, instruction sequences.
  8161.  
  8162. If you are interested in the straight-line execution times for some
  8163. instruction(s), placing those instructions in a tight loop may dramatically
  8164. affect IBM/L's accuracy.  Don't forget, executing a control transfer instruct-
  8165. ion (necessary for a loop) flushes the pre-fetch queue and has a big effect
  8166. on execution times.  The "#UNRAVEL" statement lets you copy a block of code
  8167. several times in place (like unravelling a loop) thereby reducing the overhead
  8168. of the conditional jump instructions controlling the loop.  The "#UNRAVEL"
  8169. statement takes the following form:
  8170.  
  8171.     #UNRAVEL count
  8172.  
  8173. (The "#" must be in column one).  "count" is a 16-bit integer constant
  8174. denoting the number of times IBM/L is to repeat the code in place.
  8175.  
  8176. Note that the specified code sequence in the #CODE section will actually
  8177. be executed (count*value1*value2) times, since the #UNRAVEL statement
  8178. repeats the code sequence "count" times inside the loop.
  8179.  
  8180. In its most basic form, the #CODE section looks like the following:
  8181.  
  8182.     #CODE ("Title")
  8183.     %DO
  8184.  
  8185.         <assembly statements>
  8186.  
  8187.     #ENDCODE
  8188.  
  8189. The title can be any string you choose.  IBM/L will display this title
  8190. when printing the timing results for this code section.  IBM/L will take
  8191. the specified assembly statements and output them (multiple times if the
  8192. #UNRAVEL statement specifies) inside a loop.  At run time the generated
  8193. assembly language source file will time this code and present a count,
  8194. in ticks, for one execution of this sequence.
  8195.  
  8196. Example:
  8197.  
  8198. #unravel 16            Execute the sequence 16 times inside the loop
  8199. #repetitions 32, 30000        Do this 32*30000 times
  8200. #code ("MOV AX, 0  Instruction")
  8201. %do
  8202.         mov    ax, 0
  8203. #endcode
  8204.  
  8205. The above code would generate an assembly language program which executes
  8206. the MOV AX, 0 instruction 16 * 32 * 30000 times and report the amount of
  8207. time that it would take.
  8208.  
  8209. Most IBM/L programs have multiple code sections.  New code sections can
  8210. immediately follow the previous ones, e.g.,
  8211.  
  8212. #unravel 16            Execute the sequence 16 times inside the loop
  8213. #repetitions 32, 30000        Do this 32*30000 times
  8214. #code ("MOV AX, 0  Instruction")
  8215. %do
  8216.         mov    ax, 0
  8217. #endcode
  8218.  
  8219. #code ("XOR AX, AX Instruction")
  8220. %do
  8221.         xor    ax, ax
  8222. #ENDCODE
  8223.  
  8224. The above sequence would execute the MOV AX, 0 and XOR AX, AX instructions
  8225. 16*32*30000 times and report the amount of time necessary to perform
  8226. these instructions.  By comparing the results you can determine which
  8227. instruction sequence is fastest.
  8228.  
  8229. All IBM/L programs must end with a "#END" statement.  Therefore, the
  8230. correct form of the instruction above is
  8231.  
  8232. #unravel 16            Execute the sequence 16 times inside the loop
  8233. #repetitions 32, 30000        Do this 32*30000 times
  8234. #code ("MOV AX, 0  Instruction")
  8235. %do
  8236.         mov    ax, 0
  8237. #endcode
  8238.  
  8239. #code ("XOR AX, AX Instruction")
  8240. %do
  8241.         xor    ax, ax
  8242. #ENDCODE
  8243. #END
  8244.  
  8245.  
  8246.  
  8247. An example of a complete IBM/L program using all of the techniques we've
  8248. seen so far is
  8249.  
  8250. #data
  8251.     even
  8252. i    dw    ?
  8253.     db    ?
  8254. j    db    ?
  8255. #enddata
  8256. #unravel 16            Execute the sequence 16 times inside the loop
  8257. #repetitions 32, 30000        Do this 32*30000 times
  8258. #code ("Aligned Word MOV")
  8259. %do
  8260.         mov    ax, i
  8261. #endcode
  8262.  
  8263. #code ("Unaligned word MOV")
  8264. %do
  8265.         mov    ax, j
  8266. #ENDCODE
  8267. #END
  8268.  
  8269.  
  8270.  
  8271.  
  8272. There are a couple of optional sections which may appear between the
  8273. "#CODE" and the "%DO" statements.  The first of these is "%INIT" which begins
  8274. an initialization section.  IBM/L emits initialization sections before the
  8275. loop and does not count their execution time when timing the loop.  This lets
  8276. you set up important values prior to running a test which do not count
  8277. towards the timing.  E.g.,
  8278.  
  8279. #data
  8280. i        dd    ?
  8281. #enddata
  8282.  
  8283. #repetitions 5,20000
  8284. #unravel 1
  8285. #code
  8286. %init
  8287.         mov    word ptr i, 0
  8288.         mov    word ptr i+2, 0
  8289. %do
  8290.         mov    cx, 200
  8291. lbl:        inc    word ptr i
  8292.         jnz    NotZero
  8293.         inc    word ptr i+2
  8294. NotZero:    loop    lbl
  8295. #endcode
  8296. #end
  8297.  
  8298. The code in the "%INIT" section executes only once and does not affect the
  8299. timing.
  8300.  
  8301.  
  8302. Sometimes you may want to use the "#UNRAVELS" statement to repeat a section
  8303. of code several times.  However, there may be some statements which you
  8304. only want to execute once on each loop (that is, without copying the code
  8305. several times in the loop).  The "%eachloop" section allows this.  Note that
  8306. the code executed in the "%eachloop" section is not counted in the final
  8307. timing.
  8308.  
  8309. Example:
  8310.  
  8311. #data
  8312. i        dw    ?
  8313. j        dw    ?
  8314. #enddata
  8315.  
  8316. #repetitions 2,20000
  8317. #unravel 128
  8318. #code
  8319. %init      -- The following is executed only once
  8320.  
  8321.         mov    i, 0
  8322.         mov    j, 0
  8323.  
  8324. %eachloop  -- The following is executed only 40000 times, not 128*40000 times
  8325.         
  8326.         inc    j
  8327.  
  8328. %do
  8329.         inc    i
  8330.  
  8331. #endcode
  8332. #end
  8333.  
  8334. In the above code, IBM/L only counts the time required to increment i.  It does
  8335. not time the instructions in the %init or %eachloop sections.
  8336.  
  8337. The code in the %eachloop section only executes once per loop iteration.  Even
  8338. if you use the "#unravel" statement (the "inc i" instruction above, for
  8339. example, executes 128 times per loop iteration because of #UNRAVEL).  Sometimes
  8340. you may want some sequence of instructions to execute like those in the %do
  8341. section, but not get timed.  The "%discount" section allows for this.
  8342. Here is the full form of an IBM/L source file:
  8343.  
  8344. #DATA
  8345.     <data declarations>
  8346. #ENDDATA
  8347.  
  8348. #REPETITIONS value1, value2
  8349. #UNRAVEL count
  8350. #CODE
  8351. %INIT
  8352.     <Initialization code, executed only once>
  8353. %EACHLOOP
  8354.     <Loop initialization code, executed once on each pass through the loop>
  8355. %DISCOUNT
  8356.     <Untimed statements, executed each time the %DO section executes>
  8357. %DO
  8358.     <The statements you want to time>
  8359. #ENDCODE
  8360.  
  8361. <additional code sections>
  8362.  
  8363. #END
  8364.  
  8365. There are several sample files which demonstrate each of these sections
  8366. included with this package.
  8367.  
  8368.  
  8369. --------------------------------
  8370.  
  8371. How to use IBM/L
  8372.  
  8373. IBM/L was created using FLEX and BISON.  As per FSF's license (indeed, going
  8374. beyond what they request) this package includes all the sources (C, ASSEMBLY,
  8375. FLEX, and BISON) for the program.  Feel free to modify it as you see fit.
  8376.  
  8377. To use this package you need several files.  IBML.EXE is the executable
  8378. program.  You run it as follows:
  8379.  
  8380.     c:> IBML filename.IBM
  8381.  
  8382. This reads an IBML source file (filename.IBM, above) and writes an assembly
  8383. language program to the standard output.  Normally you would use I/O
  8384. redirection to capture this program as follows:
  8385.  
  8386.     c:> IBML filename.IBM >filename.ASM
  8387.  
  8388. Once you create the assembly language source file, you can assemble and run
  8389. it.  The resulting EXE file will display the timing results.
  8390.  
  8391. To properly run the IBML program, you must have the "IBMLINC.A" file in the
  8392. current working directory.  This is a skeleton assembly language source file
  8393. into which IBM/L inserts your assembly source code.  Feel free to modify this
  8394. file as you see fit.  Keep in mind, however, that IBM/L expects certain
  8395. markers in the file (currently ";##") where it will insert the code.
  8396. Be careful how you deal with these existing markers if you modify the
  8397. IBMLINC.A file.
  8398.  
  8399. The output assembly language source file assumes the presence of the
  8400. UCR Standard Library for 80x86 Assembly Language Programmers.  In particular,
  8401. it needs the STDLIB include files (stdlib.a) and the library file (stdlib.lib).
  8402.  
  8403. These must be present (or in your INCLUDE/LIB environment paths) or MASM
  8404. will not be able to properly assemble the output assembly language file.
  8405.  
  8406. There is a batch file included in this package which demonstrates the steps
  8407. necessary to run IBM/L on a test file.Character Set Routines
  8408. ----------------------
  8409.  
  8410. The character set routines let you deal with groups of characters as a set
  8411. rather than a string.  A set is an unordered collection of objects where
  8412. membership (presence or absence) is the only important quality.  The stdlib
  8413. set routines were designed to let you quickly check if an ASCII character is
  8414. in a set, to quickly add characters to a set or remove characters from a set.
  8415. These operations are the ones most commonly used on character sets.  The
  8416. other operations (like union, intersection, difference, etc.) are useful, but
  8417. are not as popular as the former routines.  Therefore, the data structure
  8418. has been optimized for sets to handle the membership and add/delete operations
  8419. at the slight expense of the others.
  8420.  
  8421. Character sets are implemented via bit vectors.  A "1" bit means that an item
  8422. is present in the set and a "0" bit means that the item is absent from the
  8423. set.  The most common implementation of a character set is to use thirty-two 
  8424. consecutive bytes, eight bytes per, giving 256 bits (one bit for each char-
  8425. acter in the character set).  While this makes certain operations (like 
  8426. assignment, union, intersection, etc.) fast and convenient, other operations
  8427. (membership, add/remove items) run much slower.  Since these are the more 
  8428. important operations, a different data structure is used to represent sets.
  8429. A faster approach is to simply use a byte value for each item in the set.  
  8430. This offers a major advantage over the thirty-two bit scheme:  for operations 
  8431. like membership it is very fast (since all you have got to do is index into 
  8432. an array and test the resulting value).  It has two drawbacks:  first, oper-
  8433. ations like set assignment, union, difference, etc., require 256 operations 
  8434. rather than thirty-two; second, it takes eight times as much memory.
  8435.  
  8436. The first drawback, speed, is of little consequence.  You will rarely use the
  8437. the operations so affected, so the fact that they run a little slower will be
  8438. of little consequence.  Wasting 224 bytes is a problem, however.  Especially
  8439. if you have a lot of character sets.
  8440.  
  8441. The approach used here is to allocate 272 bytes.  The first eight bytes con-
  8442. tain bit masks, 1, 2, 4, 8, 16, 32, 64, 128.  These masks tell you which bit
  8443. in the following 264 bytes is associated with the set.  This facilitates 
  8444. putting eight sets into 272 bytes (34 bytes per character set).  This provides
  8445. almost the speed of the 256-byte set with only a two byte overhead.  In the
  8446. stdlib.a file there is a macro that lets you define a group of character
  8447. sets:  set.  The macro is used as follows:
  8448.  
  8449.     set set1, set2, set3, ... , set8
  8450.  
  8451. You must supply between one and eight labels in the operand field.  These are
  8452. the names of the sets you want to create.  The set macro automatically 
  8453. attaches these labels to the appropriate mask bytes in the set.  The actual
  8454. bit patterns for the set begin eight bytes later (from each label).  There-
  8455. fore, the byte corresponding to chr(0) is staggered by one byte for each
  8456. set (which explains the other eight bytes needed above and beyond the 256 
  8457. required for the set).  When using the set manipulation routines, you should
  8458. always pass the address of the mask byte (i.e., the seg/offset of one of the 
  8459. labels above) to the particular set manipulation routine you are using. 
  8460. Passing the address of the structure created with the macro above will 
  8461. reference only the first set in the group.
  8462.  
  8463. Note that you can use the set operations for fast pattern matching appli-
  8464. cations.  The set membership operation for example, is much faster that the 
  8465. strspan routine found in the string package.  Proper use of character sets
  8466. can produce a program which runs much faster than some of the equivalent
  8467. string operations.
  8468.  
  8469.  
  8470. Note: there is a special include file in the INCLUDE directory, STDSETS.A,
  8471. which contains the bit definitions for eight commonly-used character sets:
  8472. Alpha (upper and lower case alphabetics), lower (lower case alphabetics),
  8473. upper (upper case alphabetics), digits ("0".."9"), xdigits (hexadecimal
  8474. digits: "0"-"9", 'a'-'z', and 'A'-'Z'), alphanum (upper/lower case alpha
  8475. and digits), whitespace (spaces, tabs, carriage returns, and linefeeds),
  8476. and delimiters (whitespace plus ",", ";", "<", ">", and "|").
  8477.  
  8478. If you want to use this standard character set in your program you must
  8479. include the STDSETS.A file in an appropriate (data) segment.  Note that
  8480. including STDLIB.A or CHARSETS.A will not give the standard sets.  You must
  8481. explicitly place an include STDSETS.A in your program to have access to
  8482. these sets.
  8483.  
  8484.  
  8485. Routine:  Createsets
  8486. --------------------
  8487.  
  8488. Category:             Character Set Routine
  8489.  
  8490. Registers on Entry:   no parameters passed
  8491.  
  8492. Registers on return:  ES:DI - pointer to eight sets
  8493.  
  8494. Flags affected:       Carry = 0 if no error. Carry = 1 if insufficient
  8495.               memory to allocate storage for sets.
  8496.  
  8497. Example of Usage:
  8498.               Createsets
  8499.               jc      NoMemory
  8500.               mov     word ptr SetPtr,   di
  8501.               mov     word ptr SetPtr+2, es
  8502.  
  8503. Description:  Createsets allocates 272 bytes on the heap.   This is sufficient
  8504.           room for eight character sets.  It then initializes the first
  8505.           eight bytes of this storage with the proper mask values for
  8506.           each set.  Location es:0[di] gets set to 1, location es:1[di]
  8507.           gets 2, location es:2[di] gets 4, etc.  The Createsets routine
  8508.           also initializes all of the sets to the empty set by clearing
  8509.           all the bits to zero.
  8510.  
  8511. Include:              stdlib.a or charsets.a
  8512.  
  8513.  
  8514. Routine:  EmptySet
  8515. ------------------
  8516.  
  8517. Category:             Character Set Routine
  8518.  
  8519. Registers on Entry:   ES:DI - pointer to first byte of desired set
  8520.  
  8521. Registers on return:  None
  8522.  
  8523. Flags affected:          None
  8524.  
  8525. Example of Usage:
  8526.               les     di,  SetPtr
  8527.               add     di,  3          ; Point at 4th set in group.
  8528.               Emptyset
  8529.  
  8530.  
  8531. Description:  Emptyset clears out the bits in a character set to zero
  8532.           (thereby setting it to the empty set).  Upon entry, es:di must
  8533.           point at the first byte of the character set you want to clear.
  8534.           Note that this is not the address returned by Createsets.  The
  8535.           first eight bytes of a character set structure are the
  8536.           addresses of eight different sets.  ES:DI must point at one of
  8537.           these bytes upon entry into Emptyset.
  8538.  
  8539. Include:              stdlib.a or charsets.a
  8540.  
  8541.  
  8542. Routine:  Rangeset
  8543. ------------------
  8544.  
  8545. Category:             Character Set Routine
  8546.  
  8547. Registers on entry:   ES:DI (contains the address of the first byte of the set)
  8548.               AL    (contains the lower bound of the items)
  8549.               AH    (contains the upper bound of the items)
  8550.  
  8551. Registers on return:  None
  8552.  
  8553. Flags affected:       None
  8554.  
  8555. Example of Usage:
  8556.               lea di, SetPtr
  8557.               add di, 4
  8558.               mov al, 'A'
  8559.               mov ah, 'Z'
  8560.               rangeset
  8561.  
  8562.  
  8563. Description:  This routine adds a range of values to a set with ES:DI as the
  8564.           pointer to the set, AL as the lower bound of the set, and
  8565.           AH as the upper bound of the set (AH has to be greater than
  8566.           AL, otherwise, there will an error).
  8567.  
  8568. Include:              stdlib.a or charsets.a
  8569.  
  8570.  
  8571. Routine:  Addstr (l)
  8572. --------------------
  8573.  
  8574. Category:             Character Set Routine
  8575.  
  8576. Registers on Entry:   ES:DI- pointer to first byte of desired set
  8577.               DX:SI- pointer to string to add to set (Addstr only)
  8578.               CS:RET-pointer to string to add to set (Addstrl only)
  8579.  
  8580. Registers on Return:  None
  8581.  
  8582. Flags Affected:       None
  8583.  
  8584. Example of Usage:
  8585.               les     di, SetPtr
  8586.               add     di, 1           ;Point at 2nd set in group.
  8587.               mov     dx, seg CharStr ;Pointer to string
  8588.               lea     si, CharStr     ; chars to add to set.
  8589.               addstr                  ;Union in these characters.
  8590. ;
  8591.               les     di, SetPtr      ;Point at first set in group.
  8592.               addstrl
  8593.               db      "AaBbCcDdEeFf0123456789",0
  8594. ;
  8595.  
  8596.  
  8597. Description:  Addstr lets you add a group of characters to a set by
  8598.           specifying a string containing the characters you want in
  8599.           the set.  To Addstr you pass a pointer to a zero-terminated
  8600.           string in dx:si.  Addstr will add (union) each character
  8601.           from this string into the set.
  8602.  
  8603.           Addstrl works the same way except you pass the string as
  8604.           a literal string constant in the code stream rather than
  8605.           via ES:DI.
  8606.  
  8607. Include:              stdlib.a or charsets.a
  8608.  
  8609.  
  8610. Routine:  Rmvstr (l)
  8611. --------------------
  8612.  
  8613.  
  8614. Category:             Character Set Routine
  8615.  
  8616.  
  8617. Registers on entry:   ES:DI contains the address of first byte of a set
  8618.               DX:SI contains the address of string to be removed
  8619.                  from a set (Rmvstr only)
  8620.               CS:RET pointer to string to add to set (Rmvstrl only)
  8621.  
  8622.  
  8623. Registers on return:  None
  8624.  
  8625.  
  8626. Flags affected:       None
  8627.  
  8628.  
  8629. Example of Usage:
  8630.               les     di, SetPtr
  8631.               mov     dx, seg CharStr
  8632.               lea     si, CharStr
  8633.               rmvstr
  8634.  
  8635.               mov     dx, seg CharStr
  8636.               lea     si, CharStr
  8637.               rmvstrl
  8638.               db          "ABCDEFG",0
  8639.  
  8640.  
  8641. Description:  This routine is to remove a string from a set with ES:DI
  8642.           pointing to its first byte, and DX:SI pointing to the
  8643.           string to be removed from the set.
  8644.  
  8645.           For Rmvstrl, the string of characters to remove from the
  8646.           set follows the call in the code stream.
  8647.  
  8648. Include:              stdlib.a or charsets.a
  8649.  
  8650.  
  8651. Routine:  AddChar
  8652. -----------------
  8653.  
  8654. Category:             Character Set Routine
  8655.  
  8656. Registers on Entry:   ES:DI- pointer to first byte of desired set
  8657.               AL- character to add to the set
  8658.  
  8659. Registers on Return:  None
  8660.  
  8661. Flags affected:       None
  8662.  
  8663. Example of Usage:
  8664.               les     di, SetPtr
  8665.               add     di, 1           ;Point at 2nd set in group.
  8666.               mov     al, Ch2Add      ;Character to add to set.
  8667.               addchar
  8668.  
  8669.  
  8670. Description:  AddChar lets you add a single character (passed in AL)
  8671.           to a set.
  8672.  
  8673. Include:              stdlib.a or charsets.a
  8674.  
  8675.  
  8676. Routine:  Rmvchar
  8677. -----------------
  8678.  
  8679. Category:             Character Set Routine
  8680.  
  8681. Registers on entry:   ES:DI (contains the address of first byte of a set)
  8682.               AL    (contains the character to be removed)
  8683.  
  8684. Registers on return:  None
  8685.  
  8686. Flags affected:          None
  8687.  
  8688. Example of Usage:
  8689.               lea di, SetPtr
  8690.               add di, 7        ;Point at eighth set in group.
  8691.               mov al, Ch2Rmv
  8692.               Rmvchar
  8693.  
  8694. Description:  This routine removes the character in AL from a set.
  8695.           ES:SI points to the set's mask byte. The corresponding
  8696.           bit in the set is cleared to zero.
  8697.  
  8698. Include:              stdlib.a or charsets.a
  8699.  
  8700.  
  8701. Routine:  Member
  8702. ----------------
  8703.  
  8704. Category:             Character Set Routine
  8705.  
  8706. Registers on entry:   ES:DI (contains the address of first byte of a set)
  8707.               AL    (contains the character to be compared)
  8708.  
  8709. Registers on return:  None
  8710.  
  8711. Flags affected:       Zero flag (Zero = 0 if the character is in the set
  8712.                  Zero = 1 if the character is not in the set)
  8713.  
  8714. Example of Usage:
  8715.               les di, SetPtr
  8716.               add di, 1
  8717.               mov al, 'H'
  8718.               member
  8719.               jne IsInSet
  8720.  
  8721.  
  8722. Description:  Member is used to find out if the character in AL is in a set
  8723.           with ES:DI pointing to its mask byte. If the character is in
  8724.           the set, the zero flag is set to 0. If not, the zero flag is
  8725.           set to one.
  8726.  
  8727. Include:              stdlib.a or charsets.a
  8728.  
  8729.  
  8730. Routine:  CopySet
  8731. -----------------
  8732.  
  8733. Category:            Character Set Routine
  8734.  
  8735. Register on entry:   ES:DI- pointer to first byte of destination set.
  8736.              DX:SI- pointer to first byte of source set.
  8737.  
  8738. Register on Return:  None
  8739.  
  8740. Flags affected:      None
  8741.  
  8742. Example of Usage:
  8743.              les     di, SetPtr
  8744.              add     di, 7           ;Point at 8th set in group.
  8745.              mov     dx, seg SetPtr2 ;Point at first set in group.
  8746.              lea     si, SetPtr2
  8747.              copyset
  8748.  
  8749.  
  8750. Description:  CopySet copies the items from one set to another.  This is a
  8751.           straight assignment, not a union operation.  After the
  8752.           operation, the destination set is identical to the source set,
  8753.           both in terms of the element present in the set and absent
  8754.           from the set.
  8755.  
  8756.  
  8757. Include:             stdlib.a or charsets.a
  8758.  
  8759.  
  8760. Routine:  SetUnion
  8761. ------------------
  8762.  
  8763. Category:            Character Set Routine
  8764.  
  8765. Register on entry:   ES:DI - pointer to first byte of destination set.
  8766.              DX:SI - pointer to first byte of source set.
  8767.  
  8768. Register on return:  None
  8769.  
  8770. Flags affected:      None
  8771.  
  8772. Example of Usage:    les   di, SetPtr
  8773.              add   di, 7              ;point at 8th set in group.
  8774.              mov   dx, seg SetPtr2    ;point at 1st set in group.
  8775.              lea   si, sSetPtr2
  8776.              unionset
  8777.  
  8778.  
  8779. Description:  The SetUnion routine computes the union of two sets.
  8780.           That is, it adds all of the items present in a source set
  8781.           to a destination set.  This operation preserves items
  8782.           present in the destination set before the SetUnion
  8783.           operation.
  8784.  
  8785. Include:             stdlib.a or charsets.a
  8786.  
  8787.  
  8788. Routine:  SetIntersect
  8789. ----------------------
  8790.  
  8791. Category:            Character Set Routine
  8792.  
  8793. Register on entry:   ES:DI - pointer to first byte of destination set.
  8794.              DX:SI - pointer to first byte of source set.
  8795.  
  8796. Register on return:  None
  8797.  
  8798. Flags affected:      None
  8799.  
  8800. Example of Usage:
  8801.              les   di, SetPtr
  8802.              add   di, 7              ;point at 8th set in group.
  8803.              mov   dx, seg SetPtr2    ;point at 1st set in group.
  8804.              lea   si, SetPtr2
  8805.              setintersect
  8806.  
  8807. Description:  SetIntersect computes the intersection of two sets, leaving
  8808.           the result in the destination set.  The new set consists
  8809.           only of those items which previously appeared in
  8810.           both the source and destination sets.
  8811.  
  8812. Include:             stdlib.a or charsets.a
  8813.  
  8814.  
  8815. Routine:  SetDifference
  8816. -----------------------
  8817.  
  8818. Category:            Character Set Routine
  8819.  
  8820. Register on entry:   ES:DI - pointer to the first byte of destination set.
  8821.              DX:SI - pointer to the first byte of the source set.
  8822.  
  8823. Register on return:  None
  8824.  
  8825. Flags affected:      None
  8826.  
  8827. Example of Usage:
  8828.              les   di, SetPtr
  8829.              add   di, 7               ;point at 8th set in group.
  8830.              mov   dx, seg SetPtr2     ;point at 1st set in group.
  8831.              lea   si, SetPtr2
  8832.              setdifference
  8833.  
  8834.  
  8835. Description:  SetDifference computes the result of (ES:DI) := (ES:DI) -
  8836.           (DX:SI).  The destination set is left with its original
  8837.           items minus those items which are also in the source set.
  8838.  
  8839. Include:             stdlib.a or charsets.a
  8840.  
  8841.  
  8842. Routine:  Nextitem
  8843. ------------------
  8844.  
  8845. Category:             Character Set Routine
  8846.  
  8847. Registers on entry:   ES:DI (contains the address of first byte of the set)
  8848.  
  8849. Registers on return:  AL (contains the first item in the set)
  8850.  
  8851. Flags affected:       None
  8852.  
  8853. Example of Usage:
  8854.               les di, SetPtr
  8855.               add di, 7        ;Point at eighth set in group.
  8856.               nextitem
  8857.  
  8858.  
  8859. Description:  Nextitem is the routine to search the first character (item)
  8860.           in the set with ES:DI pointing to its mask byte. AL will
  8861.           return the character in the set. If the set is empty, AL
  8862.           will contain zero.
  8863.  
  8864. Include:              stdlib.a or charsets.a
  8865.  
  8866.  
  8867. Routine:  Rmvitem
  8868. -----------------
  8869.  
  8870. Category:             Character Set Routine
  8871.  
  8872. Registers on entry:   ES:DI (contains the address fo first byte of the set)
  8873.  
  8874. Registers on return:  AL (contains the first item in the set)
  8875.  
  8876. Flags affected:       None
  8877.  
  8878. Example of Usage:
  8879.               les di, SetPtr
  8880.               add di, 7
  8881.               rmvitem
  8882.  
  8883. Description:  Rmvitem locates the first available item in the set and
  8884.           removes it with ES:DI pointing to its mask byte. AL will
  8885.           return the item removed. If the set is empty, AL will
  8886.           return zero.
  8887.  
  8888. Include:              stdlib.a or charsets.a
  8889.  
  8890.  
  8891. Pattern Matching Routines
  8892. -------------------------
  8893.  
  8894. The UCR Standard Library contains a very rich set of (character string)
  8895. pattern matching routines.  These routines were designed to mimic the
  8896. pattern matching primitives found in the SNOBOL4 programming language, so
  8897. they are very powerful indeed.
  8898.  
  8899. These routines are actually quite simple.  They derive their power through
  8900. the use of a recursive, backtracking pattern matching algorithm and a
  8901. properly specified data structure: the "pattern".  The data type for a
  8902. pattern is the following:
  8903.  
  8904. Pattern        struc
  8905. MatchFunction    dd    ?
  8906. MatchParm    dd    0
  8907. MatchAlternate    dd    0
  8908. NextPattern    dd    0
  8909. EndPattern    dw    ?
  8910. StartPattern    dw    ?
  8911. StrSeg        dw    ?
  8912. Pattern        ends
  8913.  
  8914.  
  8915. The "MatchFunction" field is a pointer to a (far) procedure which tests the
  8916. current characters in the string.  You could write your own functions for
  8917. this purpose if you choose, however, several important routines are already
  8918. provided in this package.
  8919.  
  8920. "MatchParm" represents a four-byte value which the pattern matching algorithm
  8921. passes to the MatchFunction routine.  Typically it is a pointer to a string
  8922. or a character set though it could be any four-byte value.
  8923.  
  8924. "MatchAlternate" is a pointer to an alternate pattern to try if the current
  8925. pattern fails to match the string.
  8926.  
  8927. "NextPattern" is a pointer to another pattern in the current pattern list.
  8928. This lets you concatenate patterns to form more complex patterns.
  8929.  
  8930. "EndPattern", "StartPattern", and "StrSeg" are words filled in by the pattern
  8931. matching routine so other code can locate the characters matched by this
  8932. particular pattern.  In general, you should not modify these values.
  8933.  
  8934.  
  8935. The MatchFunction is where most of the work actually takes place.  Currently
  8936. the standard library provides 18 different MatchFunctions:
  8937.  
  8938.             Spancset
  8939.             Brkcset
  8940.             MatchStr
  8941.             MatchiStr
  8942.             MatchToStr
  8943.             MatchChar
  8944.             MatchToChar
  8945.             MatchChars
  8946.             MatchToPat
  8947.             Anycset
  8948.             NotAnycset
  8949.             EOS
  8950.             ARB
  8951.             ARBNUM
  8952.             Skip
  8953.             POS
  8954.             RPOS
  8955.             GOTOpos
  8956.         and    RGOTOpos
  8957.  
  8958.  
  8959. Note: in order to gain access to these match functions you must place the
  8960. statement:
  8961.  
  8962.             matchfuncs
  8963.  
  8964. somewhere in your program after including "pattern.a" or "stdlib.a".  This
  8965. macro defines the externals for the match functions.  Since these match
  8966. functions do not get called in the same manner as other standard library
  8967. routines, they do not get automatically linked with your programs.  There
  8968. is a comment in the "shell.asm" file which activates this macro.  Uncomment
  8969. this line and you'll be in great shape.
  8970.  
  8971.  
  8972. A brief description of the matching functions:
  8973.  
  8974. Spancset will match any number of characters belonging to a character set.
  8975. (This includes zero characters.)  You specify the character set via a pointer
  8976. to a UCR Stdlib CSET.  The pointer to this character set goes in the
  8977. "MatchParm" field of the above structure.
  8978.  
  8979. Brkcset will match any number of characters which are *not* in a character
  8980. set.  That is, it will match up to a character in the specified character
  8981. set or until the end of the string, whichever comes first.  Once again,
  8982. "MatchParm" contains a pointer to the character set to use.
  8983.  
  8984. MatchStr matches a specified string (something like the strcmp routine).
  8985. The "MatchParm" field points at the zero terminated string to match.
  8986.  
  8987. MatchiStr is like MatchStr except it converts the input string to uppercase
  8988. before comparing against the specified string (the specified string should
  8989. contain all upper case characters or it will not match).
  8990.  
  8991. MatchToStr matches all characters in a string up to and including the
  8992. string specified by the "MatchParm" field.
  8993.  
  8994. MatchChar matches a single character.  This character must appear in the
  8995. L.O. byte of the "MatchParm" field.  Note that this routine must match
  8996. exactly one character.
  8997.  
  8998. MatchChars matches zero or more occurrences of the same character.  Again,
  8999. the character appears in the L.O. byte of the "MatchParm" field.
  9000.  
  9001. MatchToChar matches all characters up to, and including, the character
  9002. specified in the L.O. byte of the "MatchParm" field.
  9003.  
  9004. MatchToPat matches all characters up to, and including, the characters
  9005. matched by the pattern specified in the "MatchParm" field.
  9006.  
  9007. Anycset matches a single character from a character set.  As usual, the
  9008. "MatchParm" field points at the character set to test.
  9009.  
  9010. NotAnycset matches a single character which is *not* in the specified
  9011. character set.  Once again, "MatchParm" points at the character set to use.
  9012.  
  9013. EOS matches the end of the string (that is, the zero terminating byte).
  9014.  
  9015. ARB matches an arbitrary number of characters.
  9016.  
  9017. ARBNUM matches an arbitrary (zero or more) number of strings matching the
  9018. pattern specified in the "MatchParm" field.
  9019.  
  9020. Skip matches "n" arbitrary characters.  The number of characters to skip is
  9021. specified in the L.O. word of the "MatchParm" field.
  9022.  
  9023. POS matches if the matching routine is currently at position "n" in the
  9024. string.  "n" is given by the L.O. word of the "MatchParm" field.
  9025.  
  9026. RPOS matches if the matching routine is currently at position "n" from the
  9027. end of the string.  Again, "n" is the L.O. word of the "MatchParm" field.
  9028.  
  9029. GOTOpos moves to the position in the string specified by the L.O. word of
  9030. the "MatchParm" field.  This routine fails if it tries to move backwards in
  9031. the string or it attempts to move beyond the end of the string.
  9032.  
  9033. RGOTOpos moves to the position in the string "n" chars from the end of the
  9034. string ("n" being the L.O. word of "MatchParm").  Fails if this moves you
  9035. backwards in the string.
  9036.  
  9037. To understand how to use these routines, a little pattern matching theory
  9038. is in order.  Pattern matching is quite similar to string comparison except
  9039. you don't need to match an exact string.  Instead, you can specify arbitrary
  9040. *patterns* of characters to match.  For example, an indentifier in a high
  9041. level language like Pascal consists of an alphabetic character following by
  9042. zero or more alphanumeric characters.  You cannot perform a single string
  9043. comparison which will accept all possible Pascal identifiers (indeed, that
  9044. single comparison would only accept a single Pascal identifier).  However,
  9045. you can easily create a pattern which will accept all Pascal ids:
  9046.  
  9047.     Anycset(A-Za-z) Spancset(A-Za-z0-9)
  9048.  
  9049. Anycset above matches a single character from the specified set (alphabetic)
  9050. and the Spancset function matches zero or more characters from the alpha-
  9051. numeric character set.  If you were to take a character string and *match*
  9052. it against the above pattern, the match would __succeed__ if the string is a
  9053. valid Pascal identifier, it would __fail__ if the string is not a valid
  9054. Pascal identifier.
  9055.  
  9056. Note, by the way, that the above pattern actually matches any string which
  9057. *begins* with a valid Pascal identifier.  If the match routine exhausts
  9058. the pattern before exhausting characters in the string, it considers the
  9059. match successful.  If you wanted to match *only* a Pascal identifier you
  9060. would use a pattern like the following:
  9061.  
  9062.     Anycset(A-Za-z) Spancset(A-Za-z0-9) EOS
  9063.  
  9064. The "EOS" pattern matches the end of the string, so this pattern matches Pascal
  9065. identifiers only.
  9066.  
  9067. Of course, you can use pattern matching to perform string comparisons using
  9068. the MatchStr function:
  9069.  
  9070.     MatchStr("Hello world") EOS
  9071.  
  9072. However, this is a frightfully expensive way to do a simple string comparison.
  9073. (Okay, it really isn't that bad, but it does take several times longer than,
  9074. say, strcmp.)
  9075.  
  9076. Although you wouldn't match character strings this way, using strings within
  9077. patterns is quite useful.  Consider the following which matches
  9078.         "value=<fp number>"
  9079. where "<fp number>" denotes a decimal value:
  9080.  
  9081.     MatchStr("value=") Spancset(0-9) MatchChar('.') Spancset(0-9)
  9082.  
  9083. This pattern requires that the string begin with "value=<fp number>" though
  9084. anything could follow the decimal value in the string.  If you wanted the
  9085. string to exactly match the above pattern, you could put an EOS at the end
  9086. of the pattern.
  9087.  
  9088. What if you wanted to test for the presence of the above pattern *anywhere*
  9089. in the string (not necessarily at the beginning)?  This is easily accomplished
  9090. by the pattern:
  9091.  
  9092.     ARB MatchStr("value=") Spancset(0-9) MatchChar('.') Spancset(0-9)
  9093.  
  9094. ARB matches an arbitrary number of characters.  At first you might think
  9095. "gee, if it matches any number of characters, what's to prevent it from
  9096. matching everything to the end of the string and causing the rest of the
  9097. pattern to fail?"  Well, simply put, the pattern matching algorithm tries
  9098. its absolute best to succeed.  So ARB will match must enough characters
  9099. so that the string "value=<fp number>" will match the rest of the pattern,
  9100. if it is present in the string.  To achieve this, the matching algorithm
  9101. usings *backtracking*.  In a nutshell, backtracking works as follows:
  9102. the current pattern matches as many characters as it can (all of them in the
  9103. case of ARB).  It then tries to match the remaining characters against the
  9104. rest of the pattern.  If that fails, then it backs up and tries again
  9105. (logically you can think of ARB giving up one character at a time from the
  9106. end of the string until the remaining patterns match).  If there is no match
  9107. after backing up back to the starting point, the whole pattern fails.
  9108. If this sounds expensive (slow), well, it is.  That's why you would never
  9109. try and use the pattern matching primitives for simple string comparisons.
  9110. That's also why you should try to avoid two adjacent patterns which match
  9111. the same set of characters (since ARB matches anything, it will match the
  9112. same characters as any adjacent pattern, hence it may be slow).
  9113.  
  9114. Another important feature to this pattern matching system is the ability
  9115. to do *alternation*.  Consider the following:
  9116.  
  9117.     MatchStr("black") | MatchStr("blue")
  9118.  
  9119. The "|" symbol above denotes alternation, and is read as "or".  This pattern
  9120. matches the string "black" *or* the string "blue".  Okay, now consider the
  9121. following (very typical example in pattern matching):
  9122.  
  9123. [MatchStr("black") | MatchStr("blue")] [MatchStr("bird") | MatchStr("berry")]
  9124.  
  9125. The above pattern matches the strings "blackbird", "bluebird", "blackberry",
  9126. or "blueberry".  The alternation operator lets you choose "black" or "blue"
  9127. from the first pattern and "bird" or "berry" from the second pattern.
  9128.  
  9129. This description of pattern matching theory could go on for quite some time,
  9130. but this is not the place for it.  This discussion is intended to serve as
  9131. only an appetizer for you.  If you want additional information on pattern
  9132. matching theory, pick up any SNOBOL4 manual, especially "Algorithms in
  9133. SNOBOL4" (by Gimpel, if I remember correctly).  Also, copies of Vanilla
  9134. SNOBOL are floating around with an electronic manual.  Among other things,
  9135. this contains the phone number and all of Catspaw which sells SNOBOL4 and
  9136. ICON products for various systems.  They sell several texts on SNOBOL4 and
  9137. ICON (which are pattern matching languages).  Since these library routines
  9138. are based on SNOBOL4, taking a look at SNOBOL4 will provide some insight
  9139. into these routines.
  9140.  
  9141. Now let's talk about how to actually specify a pattern in assembly language
  9142. using the pattern matching routines.  As you probably figured out already,
  9143. you don't get to use the nice (SNOBOL4-like) syntax used the preceding
  9144. examples.  Indeed, if there is any pain associated with pattern matching
  9145. in this package, it's setting up the patterns in the first place.
  9146.  
  9147. A pattern is a linked list of objects all of type "PATTERN" (see the
  9148. structure definition earlier).  You must fill in all but the last three
  9149. fields of this structure (or live with the default value of zero).
  9150. The Pascal identifier pattern mentioned above would look something
  9151. like the following:
  9152.  
  9153. pasid        pattern    <Anycset,alphabetic,0,pasid2>
  9154. pasid2      pattern    <Spanscet,alphanum>
  9155.  
  9156. (note: alphabetic and alphanum are standard character sets available in
  9157.        UCR standard library.  See the section on character sets for details).
  9158.  
  9159. The first pattern matches a single character from the "alphabetic" character
  9160. set.  The second pattern matches zero or more characters from the "alphanum"
  9161. character set.  In both cases the alternate field is zero (NULL/NIL) because
  9162. there is no alternate to match.  In the first pattern above, the NextPattern
  9163. field contains the link to the "pasid" pattern which concatenates the two
  9164. patterns.  Pasid2 has no link field since it is the last pattern in the
  9165. list (if the field is not present, it defaults to zero/NIL/NULL).
  9166.  
  9167. To actually match a string against a pattern you load ES:DI with the address
  9168. of the string to test and DX:SI with the address of the first pattern in
  9169. your pattern list.  CX contains the offset of the last character you wish
  9170. to check in the string (set CX to zero if you want to match all characters
  9171. in the string). Then you execute the "match" procedure.  On return, the
  9172. carry flag denotes success (C=1) or failure (C=0), AX contains the offset
  9173. of the character in the string immediately after the match.
  9174.  
  9175.         lesi    MyString
  9176.         ldxi    MyPattern
  9177.         mov    cx, 0
  9178.         match
  9179.         jc    TheyMatched
  9180.  
  9181. By default, all patterns match characters at the beginning of the string.
  9182. As you've seen earlier in the document, you can use ARB to allow the
  9183. pattern to match at some other point in the string.  For example, the following
  9184. matches any string which contains one or more alphabetic characters followed
  9185. by one or more decimal digits:
  9186.  
  9187. HasAnAlpha    pattern    <ARB,0,0,HAA2>
  9188. HAA2        pattern    <Anycset,alphabetic,0,HAA3>
  9189. HAA3        pattern    <Spancset,alphabetic,0,HAA4>
  9190. HAA4        pattern    <Anycset,digits>
  9191.  
  9192. Since ARB does not require any parameters, you can use any value for the
  9193. second parameter to "pattern".  Zero is as good a value as any other.
  9194. Note that "Spancset" by itself would not be sufficient for the alphabetic
  9195. matches.  Spancset matches zero or more characters.  We need to match one
  9196. or more characters.  That is why the pattern above needs the Anycset and
  9197. Spancset patterns.
  9198.  
  9199. The above pattern data type matches its pattern *anywhere* in the target
  9200. string.  If you wanted to force a match at the end of the string, you could
  9201. use the following pattern:
  9202.  
  9203. HasAnAlpha    pattern    <ARB,0,0,HAA2>
  9204. HAA2        pattern    <Anycset,alphabetic,0,HAA3>
  9205. HAA3        pattern    <Spancset,alphabetic,0,HAA4>
  9206. HAA4        pattern    <Anycset,digits,0,HAA5>
  9207. HAA5        pattern    <Spancset,digits,0,HAA6>
  9208. HAA6        pattern    <EOS>
  9209.  
  9210. EOS doesn't require a parameter, so the above lets all the fields except the
  9211. function name default to zero.
  9212.  
  9213. The MatchAlternate field contains the address of a pattern to match if the
  9214. current pattern fails (and *only* if the current pattern fails).  Consider
  9215. the blue/blackbird/berry pattern described earlier.  You can easily implement
  9216. that pattern with the following statements:
  9217.  
  9218. BB        pattern    <MatchString,black,bluepat,BB2>
  9219. BB2        pattern    <MatchString,berry,birdpat>
  9220. bluepat        pattern    <MatchString,blue,0,BB2>
  9221. birdpat        pattern    <MatchString,bird>
  9222.  
  9223. black        db    "black",0
  9224. blue        db    "blue",0
  9225. bird        db    "bird",0
  9226. berry        db    "berry",0
  9227.  
  9228. If you match BB against the string "blackberry" BB will match the black,
  9229. then it will go to BB2 which matches the berry.  This string doesn't use
  9230. either alternate.
  9231.  
  9232. If you match BB against the string "blueberry" BB immediately fails, so
  9233. it tries the alternate pattern, bluepat. Bluepat matches blue and then
  9234. goes on to the BB2 pattern which matches the berry.
  9235.  
  9236. If you match BB against the string "blackbird", BB matches black and then
  9237. tries to match BB2 against bird.  BB2 fails and tries its alternate (birdpat)
  9238. with matches the characters "bird".
  9239.  
  9240. If you match BB against the string "bluebird", BB fails and tries its alter-
  9241. nate, bluepat.  Bluepat matches "blue" and passes control to its next pattern,
  9242. which is BB2.  BB2 tries to match "bird" and fails, so it passes control to
  9243. its alternate, birdpat, which matches bird.
  9244.  
  9245. The example above is pretty straightforward as far as alternation is concerned.
  9246. You can create some very sophisticated patterns with the alternation field.
  9247. For example, consider the following generic pattern:
  9248.  
  9249.     [pat1 | ] [pat2 | pat3]
  9250.  
  9251. "[pat1 | ]" is an easy way of saying that pat1 is optional.  You can easily
  9252. create this pattern as follows:
  9253.  
  9254. Pat1        pattern    <pat1func,pat1parm,pat2,pat2>
  9255. Pat2        pattern    <pat2func,pat2parm,pat3>
  9256. Pat3        pattern    <pat3func,pat3parm>
  9257.  
  9258. If you match a string against Pat1 and the beginning of the string does not
  9259. match Pat1, then it tries Pat2 instead (and if that fails, it tries Pat3
  9260. before failing).  If the string begins with a pattern matched by Pat1, the
  9261. matching algorithm then looks to see if the characters matching Pat1 are
  9262. followed by some character matching Pat2 or, alternately, Pat3.
  9263.  
  9264. There are all kinds of tricky ways you can use the alternation field to
  9265. create complex patterns and control the precendence of the pattern matching
  9266. algorithm.  This short document cannot even begin to describe the
  9267. possibilities.  You will need to experiment with this capability to discover
  9268. its true potential.
  9269.  
  9270.  
  9271. Creating Your Own Pattern Functions
  9272. -----------------------------------
  9273.  
  9274. Although the UCR Stdlib pattern matching routines include many of the
  9275. functions you'll typically want to use for pattern matching, it's quite
  9276. possible you'll want to write your own pattern matching functions.  This
  9277. is actually quite easy to do.  The matching functions are all far procedures
  9278. which the Match procedure calls with the following parameters:
  9279.  
  9280. ES:DI- Points at the first character of the character string the function
  9281.        should match against.  The match function should never look at
  9282.        characters before this string and it should not look beyond the end
  9283.        of the string (which is marked by a zero terminating byte).
  9284.  
  9285. DS:SI- Contains the four-byte parameter found the the MatchParm field.
  9286.  
  9287. CX-    Contains the last position plus one in the string you're allowed
  9288.        to compare.  Note that this may or may not point at the zero term-
  9289.        inating byte.  You must not scan beyond this character.  Generally,
  9290.        you can assume the zero terminating byte is at or after this location
  9291.        in the string.
  9292.  
  9293. On return, AX must contain the address (offset into the string) of the last
  9294. character matched *plus one*.  After your pattern matches, additional patterns
  9295. following in the pattern list will begin their matching at location ES:AX.
  9296. You must also return the carry set if your match succeeded, you must return
  9297. the carry clear if your match failed.
  9298.  
  9299. Note that the MATCH procedure is fully recursive and rentrant.  So you can
  9300. call MATCH recursively from inside your match function.  This helps make
  9301. writing your own match routines much easier.  (note: actually, you need to
  9302. call MATCH2, which is the reentrant version, from inside your match functions.)
  9303.  
  9304. As an example, let's consider the example above where we wanted to match
  9305. a string of one or more alphabetic characters following by one or more
  9306. digits anywhere in a string.  Consider the following pattern:
  9307.  
  9308. HAA        pattern    <ARB,0,0,HAA2>
  9309. HAA2        pattern    <MatchAlpha,0,0,HAA3>
  9310. HAA2        pattern    <MatchDigits>
  9311.  
  9312. The MatchAlpha and MatchDigits pattern functions are not provided in the
  9313. standard library, we will have to write them.  MatchAlpha matches one or
  9314. more alphabetic characters, MatchDigits matches one or more decimal digits.
  9315. Here's the routines that implement these two functions:
  9316.  
  9317.  
  9318. ; Note that ES:DI & CX are already set up for these routines by the
  9319. ; Match procedure.
  9320.  
  9321. MatchAlpha    proc    far        ;Must be a far proc!
  9322.         push    dx
  9323.         push    si        ;Preserve modified registers.
  9324.         ldxi    Alpha1        ;Get pointer to "Match one or more
  9325.         match2            ; alpha" pattern and match it.
  9326.         pop    si
  9327.         pop    dx
  9328.         ret
  9329. MatchAlpha    endp
  9330.  
  9331. MatchDigits    proc    far        ;Must be a far proc!
  9332.         push    dx
  9333.         push    si        ;Preserve modified registers.
  9334.         ldxi    Digits1        ;Get pointer to "Match one or more
  9335.         match2            ; digits" pattern and match it.
  9336.         pop    si
  9337.         pop    dx
  9338.         ret
  9339. MatchDigits    endp
  9340.  
  9341. Alpha1        pattern    <Anycset,alpha,0,Alpha2>
  9342. Alpha2        pattern    <Spancset,alpha>
  9343.  
  9344. Digits1        pattern    <Anycset,digits,0,Digits2>
  9345. Digits2        pattern    <Spancset,digits>
  9346.  
  9347.  
  9348. Note that the MatchAlpha and MatchDigits patterns do not require any
  9349. parameters from the MatchParm field, they intrinsically know what they
  9350. need to use.
  9351.  
  9352. Another way to accomplish the above is to write a generic "one or more
  9353. occurrences of a pattern" type of pattern.  The following code implements
  9354. this:
  9355.  
  9356. ; Assume the "MatchParm" field contains a pointer to the pattern we
  9357. ; want to repeat one or more times:
  9358.  
  9359. OneOrMore    proc    far
  9360.         push    dx
  9361.         push    di
  9362.         mov    dx, ds            ;Point DX:SI at pattern.
  9363.         match2                ;Make sure we get at least 1.
  9364.         jnc    Fails
  9365. MatchMore:      mov    di, ax            ;Move on in string.
  9366.         match2
  9367.         jc    MatchMore
  9368.         pop    di
  9369.         pop    dx
  9370.         stc                ;Return success
  9371.         ret
  9372.  
  9373. Fails:        pop    di
  9374.         pop    dx
  9375.         clc                ;Return failure
  9376.         ret
  9377. OneOrMore    endp
  9378.  
  9379.  
  9380. A pattern which would match one or more alphabetics with this would be:
  9381.  
  9382. Alpha1ormore    pattern    <OneOrMore,alphaset>
  9383. AlphaSet    pattern    <Anycset,alpha>
  9384.  
  9385. You would specify the "Alpha1ormore" pattern to match one or more alphabetic
  9386. characters.
  9387.  
  9388.  
  9389. Of course, you can write any arbitrary function you choose for your match
  9390. function, you do not need to call MATCH2 from within your match function.
  9391. For example, a simple routine which matches one or more alphabetics followed
  9392. by one or more digits could be written as follows:
  9393.  
  9394. AlphaDigits    proc    far
  9395.         push    di
  9396.  
  9397.         cmp    di, cx
  9398.         jae    Failure
  9399.         mov    al, es:[di]
  9400.         and    al, 5fh            ;Convert l.c. -> U.C.
  9401.         cmp    al, 'A'
  9402.         jb    Failure
  9403.         cmp    al, 'Z'
  9404.         ja    Failure
  9405. DoTheMore0:    inc    di
  9406.         cmp    di, cx
  9407.         jae    Failure
  9408.         mov    al, es:[di]
  9409.         and    al, 5fh
  9410.         cmp    al, 'A'
  9411.         jb    TryDigits
  9412.         cmp    al, 'Z'
  9413.         jbe    DoTheMore0
  9414.  
  9415. TryDigits:    mov    al, es:[di]
  9416.         xor    al, '0'            ;See if in range '0'..'9'
  9417.         cmp    al, 10
  9418.         jae    Failure
  9419. DoTheMore1:    inc    di
  9420.         cmp    di, cx
  9421.         jae    Success
  9422.         mov    al, es:[di]
  9423.         xor    al, '0'
  9424.         cmp    al, 10
  9425.         jb    DoTheMore1
  9426. Success:    mov    ax, di            ;Return ending posn in AX.
  9427.         pop    di
  9428.         stc                ;Success!
  9429.         ret
  9430.  
  9431. Failure:    mov    ax, di            ;Return failure position.
  9432.         pop    di
  9433.         clc                ;Return failure.
  9434.         ret
  9435. AlphaDigits    endp
  9436.  
  9437.  
  9438. Note that the pattern matching function must return the failure position in
  9439. AX.  Also note that the routine must *not* search beyond the point specified
  9440. in the CX register.  These points did not appear in the previous code because
  9441. all of that was handled automatically by the MATCH2 routine.  Of course,
  9442. the matching function must set or clear the carry flag depending upon the
  9443. success of the operation.
  9444.  
  9445. There is a really sneaky way to simulate the use of parentheses in a pattern
  9446. to override the normal left-to-right evaluation of a pattern.  The SL_MATCH2
  9447. routine (which is what MATCH2 winds up calling) works quite well as a pattern
  9448. matching function.  Consider the following pattern:
  9449.  
  9450.     ParenPat    pattern    <sl_match2,HAA>
  9451.  
  9452. Now the ParenPat pattern will match anything the HAA pattern matches, however,
  9453. the system treats all of HAA as a single pattern (inside ParenPat) rather
  9454. than as a list of concatenated patterns.  This is real important when using
  9455. PATGRAB to extract portions of a pattern.  Patgrab can only extract the
  9456. characters belonging to a single pattern data structure (not a list).  However,
  9457. ParenPat above is a single pattern data structure which maintains the infor-
  9458. mation for the entire string matched by HAA.  Therefore, using patgrab on
  9459. ParenPat will extract the entire string matched by HAA.
  9460.  
  9461. Parenthetical operations can also simplify other patterns.  Keep in mind,
  9462. however, that the Alternate pointer field in the pattern structure can
  9463. also be used to simulate parenthetical patterns without the expense of
  9464. generating new patterns (see the previous examples).
  9465.  
  9466.  
  9467. A Note About Performance:
  9468.  
  9469. There are two aspects to efficiency programmers worry about: speed and memory
  9470. usage.  In the worst case, this pattern matching package does not fare well
  9471. in either category.  It is possible that the routines in this package could
  9472. consume several kilobytes of stack space while matching a string;  it is also
  9473. possible that the matching would take so long that it's impractical to use
  9474. this package.  Fortunately, these worst case scenerios are pathological
  9475. cases which rarely (if ever except in synthetic programs) occur.
  9476.  
  9477. Space is the first issue to address.  Each call to Match/Match2 can push
  9478. upwards of fifty bytes onto the stack.  This is in addition to the stack
  9479. space required by the low-level matching function.  Few of the built-in
  9480. matching functions push more than six or eight bytes, but you could write
  9481. your own matching function which pushes more.  It is very easy to design
  9482. a (synthetic) pattern which forces a nested, recursive, call of MATCH2 for
  9483. each character in the string you are going to match.  In such a case, this
  9484. package could require upwards of n*50 bytes on the stack where "n" is the
  9485. length of the string.  For a string with 100 characters, you'd probably
  9486. need 5K of stack space for the pattern matching routines alone.
  9487.  
  9488. In general, patterns would rarely exhibit this type of behavior.  Most low-
  9489. level pattern matching functions match several characters at once.  Further-
  9490. more, you almost never encounter patterns in real life which require a
  9491. recursive call for each character in the string.  Instead, most complex
  9492. patterns consist of simpler patterns concatenated together in a list.  This
  9493. does not require a nested recursive call for each character in the string,
  9494. rather, the package makes a call, matches some characters, then returns;  next,
  9495. the routines call the next sub-pattern in a similar fashion.  Note however,
  9496. that the state (stack space) for the previous sub-pattern has been reclaimed
  9497. from the stack at that point.
  9498.  
  9499. In practice, a typical pattern might require as much as 1K free stack space.
  9500. However, keep in mind that this is a "typical worst case value" not an
  9501. absolute worst case value.  Of course, you can control the amount of stack
  9502. space the pattern matching algorithms use by avoiding recursive pattern
  9503. definitions and avoiding parenthetical patterns (which stack up machine
  9504. state recursively) in complex patterns.  Of course, limiting the size of
  9505. the strings you're matching the pattern against will help as well.
  9506.  
  9507. Generally, the stack space used by the pattern matching algorithm is of
  9508. little concern.  Setting aside an extra kilobyte of memory, even five
  9509. kilobytes of memory, isn't a big problem for most programmers.  Speed,
  9510. on the other hand, can be a problem.  This pattern matching package uses
  9511. a generalized backtracking pattern matching algorithm.  You can easily
  9512. devise a pattern which runs in O(x**n) time where "x" is an arbitrary value
  9513. you get to pick (basically the number of possible alternations on each
  9514. sub-pattern in the pattern) and "n" is the length of the string you match.
  9515. The "O()" function notation simply means that if it takes "m" units of time
  9516. with a string of length "n", it will take "m*x" units of time for a string
  9517. of length "x+1".  Not very good.  For some patterns it could easily take
  9518. longer than your lifetime to match a string whose length is 100 characters.
  9519.  
  9520. Once again, we're fortunate in the sense that this terrible performance occurs
  9521. so rarely you need not be too concerned about it.  To achieve such bad per-
  9522. formance requires a specially prepared pattern matching a specially prepared
  9523. string.  Such combinations do not normally exist in nature!  However, while
  9524. 100 year matching times may not occur much, most programmers are interested
  9525. in having their patterns match in milliseconds.  It is very easy to devise
  9526. a pattern which takes seconds, minutes, or possibly even hours, to match
  9527. some types of strings (second timing is very likely for some common strings
  9528. and patterns, minutes is rather rare, hours is very rare, but still much
  9529. more possible than the 100 year problem).  The really sad part is that slow
  9530. matching times is almost always due to a poor choice of pattern rather than
  9531. an intrinsic problem with the pattern matching algorithm.
  9532.  
  9533. Typically, all performance problems are directly related to the amount of
  9534. backtracking which must occur to match a pattern.  Backtracking almost always
  9535. occurs which you have two adjacent sub-patterns in a pattern where the
  9536. end of the first sub-pattern matches strings from the same set as the front
  9537. of the second sub-pattern.  Consider the following pattern:
  9538.  
  9539.          spancset(a-z " " ",") matchstr("hello")
  9540.  
  9541. If you match this pattern against the string "hi there, hello" the first
  9542. spancset pattern matches the entire string.  The matchstr function would then
  9543. fail.  At this point, backtracking kicks in and backs up one character in the
  9544. string.  To the spancset function matches "hi there, hell" and the matchstr
  9545. function fails on "o".  So the algorithm backs up one more character and
  9546. tries again.  It keeps doing this until it backs up all the way to the
  9547. point where spancset matches "hi there, " and matchstr finally matches
  9548. "hello".  To get around this problem, a better choice of pattern is probably
  9549. in order.  Consider the following which generally does the same thing:
  9550.  
  9551.         matchtostr("hello")
  9552.  
  9553. Matchtostr skips over all characters in a string up to the string "hello"
  9554. and leaves the "match cursor" pointing just beyond the "o" in "hello".
  9555. This matches almost what the previous pattern will match but it does it a
  9556. whole lot faster.  It doesn't exactly match the previous pattern because
  9557. matchtostr matches any characters, not just (a-z " " ",") but for most
  9558. purposes this is exactly what you want anyway.
  9559.  
  9560. ARB is probably one of the worst offenders.  Anytime you use ARB (with
  9561. a sub-pattern following it in the pattern list), you are almost guaranteed
  9562. that backtracking will occur.  Therefore, you should attempt to avoid the
  9563. use of ARB in patterns where performance is a consideration.
  9564.  
  9565. In general, you can often redesign a pattern data structure to avoid
  9566. overlaps in adjacent sub-patterns.  Patterns which do not have such conflicts
  9567. will generally have reasonable performance.  Of course, designing such patterns
  9568. takes more effort and testing;  so it may not be worth the effort for quick
  9569. and dirty projects.  On the other hand, if you execute the pattern match more
  9570. than a few times (or the pattern matching starts to take minutes rather than
  9571. seconds) its probably worthwhile to redo the pattern.
  9572.  
  9573. Of course, this pattern matching package is not suitable for all pattern
  9574. matching tasks.  The whole purpose of this package was to make pattern
  9575. matching in assembly language easy, not fast.  You would never, for example,
  9576. want to write a lexical analyzer for a compiler using this package.  It
  9577. would be too slow and using languages like LEX and FLEX produce faster
  9578. (much faster) lexical analyzers and it's easier to create them with LEX/FLEX
  9579. as well.  Ditto for parsers using BISON or YACC.  Likewise, there are many
  9580. times when pattern matching languages like AWK, ICON, SNOBOL4, etc., are
  9581. more appropriate than using the routines in this package.  This package is
  9582. really intended for small pattern matching tasks inside a larger assembly
  9583. language program.  For example, parsing command line parameters or
  9584. parsing input lines typed by the user to request some activity in your
  9585. assembly language program.  While it's certainly possible to write a program
  9586. whose sole purpose is to perform some pattern matching problem, using this
  9587. package may not provide any better performance than, say, a SPITBOL (compiled
  9588. SNOBOL4) program and it would probably take you longer to write than the
  9589. comparable SNOBOL4 program.
  9590.  
  9591. Routine:  MATCH
  9592. ---------------
  9593.  
  9594. Category:             Pattern Matching Routine
  9595. Author:              Randall Hyde
  9596.  
  9597. Registers on Entry:   ES:DI - pointer to source string
  9598.               DX:SI - pointer to pattern
  9599.               CX-     offset of last valid position+1 in string.
  9600.                   Zero to match entire string.
  9601.  
  9602.  
  9603. Registers on return:  AX-     Position in string where the pattern stopped
  9604.                   matching.
  9605.  
  9606.  
  9607. Flags affected:          carry-    0 denotes failure to match pattern.
  9608.                 1 denotes success.
  9609.  
  9610.  
  9611. Example of Usage:
  9612.  
  9613.         lesi    StringToTest
  9614.         ldxi    PatternToMatch
  9615.         mov    cx, 0        ;Match entire string.
  9616.         MATCH
  9617.         jnc    DidNotMatch
  9618.  
  9619. Description:
  9620.  
  9621. MATCH is the general purpose matching subroutine provided in the standard
  9622. library to perform pattern matching.  On entry, DX:SI must point at a
  9623. pattern (list) data structure.  See the pattern.a include file (and the
  9624. documentation preceeding this page) for more details on this data structure.
  9625.  
  9626. Also on entry, ES:DI should point at the first character where the pattern
  9627. matching is to begin.  This need not be the beginning of a string, ES:DI could
  9628. point into the middle of a string;  however, the pattern matching begins at
  9629. location ES:DI.
  9630.  
  9631. ES:CX, on entry, must point at the last byte to check *plus one*.  This
  9632. typically points at the zero terminating byte of a string, but it could
  9633. point at some character in the string before the zero terminating byte.
  9634. If CX contains zero upon entry to the MATCH routine, the MATCH code will
  9635. automatically point CX at the zero byte in the string pointed at by ES:DI.
  9636.  
  9637. Include:              stdlib.a or pattern.a
  9638.  
  9639. Routine:  MATCH2
  9640. ----------------
  9641.  
  9642. Category:             Pattern Matching Routine
  9643. Author:              Randall Hyde
  9644.  
  9645. Registers on Entry:   ES:DI - pointer to source string
  9646.               DX:SI - pointer to pattern
  9647.               CX-     offset of last valid position+1 in string.
  9648.  
  9649.  
  9650. Registers on return:  AX-     Position in string where the pattern stopped
  9651.                   matching.
  9652.  
  9653.  
  9654. Flags affected:          carry-    0 denotes failure to match pattern.
  9655.                 1 denotes success.
  9656.  
  9657.  
  9658. Example of Usage:
  9659.             ;Typical usage in a matching function:
  9660.  
  9661.                 ldxi    NewPattern
  9662.                 MATCH2
  9663.  
  9664. Description:
  9665.  
  9666. MATCH2 is a special, reentrant, version of MATCH.  You would normally *not*
  9667. call this routine to perform pattern matching from your main program.
  9668. Instead, this routine is intended for use inside pattern matching functions
  9669. you write yourself.  Please see the accompanying documentation for more
  9670. details.
  9671.  
  9672. Include:              stdlib.a or pattern.a
  9673.  
  9674. Routine:  patgrab
  9675. -----------------
  9676.  
  9677. Category:             Pattern Matching Routine
  9678. Author:              Randall Hyde
  9679.  
  9680. Registers on Entry:   ES:DI - pointer to a pattern structure
  9681.  
  9682. Registers on return:  ES:DI - String (on heap) corresponding to the chars
  9683.                   matched by the pattern.
  9684.  
  9685. Flags affected:          carry-  set if insufficient space on heap to allocate
  9686.                   the string.
  9687.  
  9688. Example of Usage:
  9689.  
  9690.         lesi    SomeString
  9691.         ldxi    SomePattern
  9692.         Match
  9693.         lesi    SomePattern
  9694.         patgrab
  9695.  
  9696. Description:
  9697.  
  9698. You use patgrab to extract the substring matched by some particular pattern.
  9699. You always call this routine *after* calling MATCH.  Match stores pointer
  9700. information away in the pattern data structure, patgrab extracts this infor-
  9701. mation and builds a string to your specifications.
  9702.  
  9703. To grab a string which spans several sub-patterns, you can use strcat to
  9704. combine the strings or a parenthetical pattern (see the documentation
  9705. preceding these routine descriptions for details).
  9706.  
  9707. Include:              stdlib.a or pattern.a
  9708.  
  9709. Routine:  spancset
  9710. ------------------
  9711.  
  9712. Category:             Pattern Matching Primitive
  9713. Author:              Randall Hyde
  9714.  
  9715. Registers on Entry:   N/A
  9716. Registers on return:  N/A
  9717. Flags affected:          N/A
  9718.  
  9719. Example of Usage:
  9720.  
  9721.     (Note:     Generally, spancset is only invoked in a pattern data structure.
  9722.         You would not normally call this code directly from your
  9723.         program [though it is possible, see the source listings for
  9724.         details].)
  9725.  
  9726.     SCexample    pattern    <spancset,alpha>
  9727.  
  9728. Description:
  9729.  
  9730. Spancset will skip over zero or more characters from the character set (cset)
  9731. specified by the "matchparm" field (the second operand above).  This routine
  9732. always succeeds and returns the "match cursor" pointing at the first character
  9733. position beyond the matched characters in the source string.
  9734.  
  9735. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9736.         macro to obtain the external declaration for this function).
  9737.  
  9738.  
  9739. Routine:  brkcset
  9740. -----------------
  9741.  
  9742. Category:             Pattern Matching Primitive
  9743. Author:              Randall Hyde
  9744.  
  9745. Registers on Entry:   N/A
  9746. Registers on return:  N/A
  9747. Flags affected:          N/A
  9748.  
  9749. Example of Usage:
  9750.  
  9751.     (Note:     Generally, brkcset is only invoked in a pattern data structure.
  9752.         You would not normally call this code directly from your
  9753.         program [though it is possible, see the source listings for
  9754.         details].)
  9755.  
  9756.     BCexample    pattern    <brkcset,alpha>
  9757.  
  9758. Description:
  9759.  
  9760. Brkcset skips over all characters which are *not* in the character set passed
  9761. in the "MatchParm" parameter.  This routine always succeeds.  It stops with
  9762. the match cursor pointing at the first character found in the specified char-
  9763. acter set (it does not "eat" that character).  This routine always succeeds.
  9764.  
  9765. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9766.         macro to obtain the external declaration for this function).
  9767.  
  9768.  
  9769. Routine:  matchstr
  9770. ------------------
  9771.  
  9772. Category:             Pattern Matching Primitive
  9773. Author:              Randall Hyde
  9774.  
  9775. Registers on Entry:   N/A
  9776. Registers on return:  N/A
  9777. Flags affected:          N/A
  9778.  
  9779. Example of Usage:
  9780.  
  9781.     (Note:     Generally, matchstr is only invoked in a pattern data structure.
  9782.         You would not normally call this code directly from your
  9783.         program [though it is possible, see the source listings for
  9784.         details].)
  9785.  
  9786.     MSexample    pattern    <matchstr,str2match>
  9787.     Str2Match    db    "String to match",0
  9788.  
  9789. Description:
  9790.  
  9791. Matchstr compares the next characters in the source string against the
  9792. string pointed at by the "MatchParm" parameter.  If the next set of char-
  9793. acters in the source string match, this routine succeeds and returns the
  9794. match cursor pointing one character beyond the matched string in the
  9795. source string.  If the characters do not match, this routine fails and
  9796. does not modify the match cursor.
  9797.  
  9798. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9799.         macro to obtain the external declaration for this function).
  9800.  
  9801. Routine:  matchtostr
  9802. --------------------
  9803.  
  9804. Category:             Pattern Matching Primitive
  9805. Author:              Randall Hyde
  9806.  
  9807. Registers on Entry:   N/A
  9808. Registers on return:  N/A
  9809. Flags affected:          N/A
  9810.  
  9811. Example of Usage:
  9812.  
  9813.     (Note:     Generally, matchtostr is only invoked in a pattern data struct-
  9814.         ure.  You would not normally call this code directly from your
  9815.         program [though it is possible, see the source listings for
  9816.         details].)
  9817.  
  9818.     MTSexample    pattern    <matchtostr,str2match>
  9819.     Str2Match    db    "String to match",0
  9820.  
  9821. Description:
  9822.  
  9823. MatchToStr matches all characters in a string up to *and including* the
  9824. string specified by the "MatchParm" parameter.  Note that this is a very
  9825. fast (comparatively) routine and is much faster than something like
  9826. ARB followed by MatchStr (or some other combination which will force
  9827. backtracking).  This routine fails if it cannot find the specified string
  9828. in the source string (beyond the match cursor position).
  9829.  
  9830. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9831.         macro to obtain the external declaration for this function).
  9832.  
  9833. Routine:  matchchar
  9834. -------------------
  9835.  
  9836. Category:             Pattern Matching Primitive
  9837. Author:              Randall Hyde
  9838.  
  9839. Registers on Entry:   N/A
  9840. Registers on return:  N/A
  9841. Flags affected:          N/A
  9842.  
  9843. Example of Usage:
  9844.  
  9845.     (Note:     Generally, matchchar is only invoked in a pattern data struct-
  9846.         ure.  You would not normally call this code directly from your
  9847.         program [though it is possible, see the source listings for
  9848.         details].)
  9849.  
  9850.     MCexample    pattern    <matchchar, 'a'>
  9851.  
  9852. Description:
  9853.  
  9854. Matchchar tests a single character at the current match cursor position.
  9855. If the character in the L.O. byte of "MatchParm" is equal to the current
  9856. character in the source string, this routine passes over that character
  9857. in the string and returns success.  Otherwise, it does not advance the
  9858. match cursor and returns failure.
  9859.  
  9860. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9861.         macro to obtain the external declaration for this function).
  9862.  
  9863. Routine:  matchtochar
  9864. ---------------------
  9865.  
  9866. Category:             Pattern Matching Primitive
  9867. Author:              Randall Hyde
  9868.  
  9869. Registers on Entry:   N/A
  9870. Registers on return:  N/A
  9871. Flags affected:          N/A
  9872.  
  9873. Example of Usage:
  9874.  
  9875.     (Note:     Generally, matchtochar is only invoked in a pattern data struct-
  9876.         ure.  You would not normally call this code directly from your
  9877.         program [though it is possible, see the source listings for
  9878.         details].)
  9879.  
  9880.     MTCexample    pattern    <matchtochar, 'a'>
  9881.  
  9882. Description:
  9883.  
  9884. MatchToChar matches all characters up to *and including* the character
  9885. specified by the L.O. byte of "MatchParm".  It succeeds if it finds the
  9886. character in the string (in which case it returns the match cursor pointing
  9887. just beyond the specified character).  It fails otherwise.
  9888.  
  9889. This is a relatively fast matching routine and should be used in place of
  9890. something like ARB followed by MATCHCHAR.
  9891.  
  9892. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9893.         macro to obtain the external declaration for this function).
  9894.  
  9895. Routine:  matchchars
  9896. --------------------
  9897.  
  9898. Category:             Pattern Matching Primitive
  9899. Author:              Randall Hyde
  9900.  
  9901. Registers on Entry:   N/A
  9902. Registers on return:  N/A
  9903. Flags affected:          N/A
  9904.  
  9905. Example of Usage:
  9906.  
  9907.     (Note:     Generally, matchchars is only invoked in a pattern data struct-
  9908.         ure.  You would not normally call this code directly from your
  9909.         program [though it is possible, see the source listings for
  9910.         details].)
  9911.  
  9912.     MCsexample    pattern    <matchchars, 'a'>
  9913.  
  9914. Description:
  9915.  
  9916. This routine matches zero or more occurrences of the specified character
  9917. starting at the match cursor position.  It always returns success.  If it
  9918. matches one or more characters it leaves the match cursor pointing beyond
  9919. the last matched character.
  9920.  
  9921. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9922.         macro to obtain the external declaration for this function).
  9923.  
  9924. Routine:  matchtopat
  9925. --------------------
  9926.  
  9927. Category:             Pattern Matching Primitive
  9928. Author:              Randall Hyde
  9929.  
  9930. Registers on Entry:   N/A
  9931. Registers on return:  N/A
  9932. Flags affected:          N/A
  9933.  
  9934. Example of Usage:
  9935.  
  9936.     (Note:     Generally, matchtopat is only invoked in a pattern data struct-
  9937.         ure.  You would not normally call this code directly from your
  9938.         program [though it is possible, see the source listings for
  9939.         details].)
  9940.  
  9941.     MTPexample    pattern    <matchtopat, somepat>
  9942.     SomePat        pattern    <arbitrary_pattern....>
  9943.  
  9944. Description:
  9945.  
  9946. Matchtopat matches an arbitrary number of characters up to *and including*
  9947. the characters matched by the pattern specified by the "MatchParm" parameter.
  9948. Success or failure on return depends entirely on whether or not the pattern
  9949. specified as a parameter matches at some point or another.
  9950.  
  9951. MatchToPat uses "shy" pattern matching.  That is, it first attempts to match
  9952. zero characters (the empty string) followed by the parameter pattern.  If
  9953. this succeeds, it quits.  Otherwise MatchToPat matches a single character
  9954. and tries to match the parameter pattern again.  Each time it fails it matches
  9955. one additional character and tries again until there are no more characters
  9956. in the source string, at which point it fails.
  9957.  
  9958. SNOBOL4+ programmers- MatchToPat is the pattern which is most comparble to
  9959. the ARB PAT pattern in SNOBOL4+.
  9960.  
  9961. Whether or not MatchToPat is faster than ARB (stdlib version) followed by
  9962. some other pattern depends entirely on the location of the second pattern.
  9963. ARB uses a greedy algorithm and backtracks to match any following patterns.
  9964. MatchToPat uses a shy algorithm which tries the parameter pattern first and
  9965. eats characters from the source string only if the parameter pattern fails.
  9966. If the match generally occurs earlier in the source string, MatchToPat will
  9967. be faster.  If the match occurs later in the source string, ARB/PAT will
  9968. probably be faster.  If matching generally fails, MatchToPat is marginally
  9969. faster.
  9970.  
  9971. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  9972.         macro to obtain the external declaration for this function).
  9973.  
  9974. Routine:  anycset
  9975. -----------------
  9976.  
  9977. Category:             Pattern Matching Primitive
  9978. Author:              Randall Hyde
  9979.  
  9980. Registers on Entry:   N/A
  9981. Registers on return:  N/A
  9982. Flags affected:          N/A
  9983.  
  9984. Example of Usage:
  9985.  
  9986.     (Note:     Generally, anycset is only invoked in a pattern data struct-
  9987.         ure.  You would not normally call this code directly from your
  9988.         program [though it is possible, see the source listings for
  9989.         details].)
  9990.  
  9991.     ACexample    pattern    <anycset, alpha>
  9992.  
  9993. Description:
  9994.  
  9995. Anycset matches a single character from the character set (cset) specified
  9996. by the "MatchParm" parameter.  If the character at the match cursor position
  9997. is in this set, anycset advances the match cursor and succeeds.  Otherwise
  9998. it does not advance the match cursor and anycset fails.
  9999.  
  10000. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10001.         macro to obtain the external declaration for this function).
  10002.  
  10003. Routine:  notanycset
  10004. --------------------
  10005.  
  10006. Category:             Pattern Matching Primitive
  10007. Author:              Randall Hyde
  10008.  
  10009. Registers on Entry:   N/A
  10010. Registers on return:  N/A
  10011. Flags affected:          N/A
  10012.  
  10013. Example of Usage:
  10014.  
  10015.     (Note:     Generally, notanycset is only invoked in a pattern data struct-
  10016.         ure.  You would not normally call this code directly from your
  10017.         program [though it is possible, see the source listings for
  10018.         details].)
  10019.  
  10020.     NACexample    pattern    <notanycset, alpha>
  10021.  
  10022. Description:
  10023.  
  10024. NotAnycset matches a single character which is *not* in character set (cset)
  10025. specified by the "MatchParm" parameter.  If the character at the match cursor
  10026. position is not in this set, notanycset advances the match cursor and succeeds.
  10027. Otherwise it does not advance the match cursor and notanycset fails.
  10028.  
  10029. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10030.         macro to obtain the external declaration for this function).
  10031.  
  10032. Routine:  EOS
  10033. -------------
  10034.  
  10035. Category:             Pattern Matching Primitive
  10036. Author:              Randall Hyde
  10037.  
  10038. Registers on Entry:   N/A
  10039. Registers on return:  N/A
  10040. Flags affected:          N/A
  10041.  
  10042. Example of Usage:
  10043.  
  10044.     (Note:     Generally, EOS is only invoked in a pattern data struct-
  10045.         ure.  You would not normally call this code directly from your
  10046.         program [though it is possible, see the source listings for
  10047.         details].)
  10048.  
  10049.     EOSexample    pattern    <EOS>
  10050.  
  10051. Description:
  10052.  
  10053. EOS matches the end of the source string (that is, the zero terminating byte
  10054. of the source string).  The standard library pattern matching package does
  10055. not require that a source string completely match a pattern for that pattern
  10056. to succeed.  Instead, the pattern need only specify a prefix of that string.
  10057. If you want the pattern to match the entire string you must stick the EOS
  10058. pattern at the end of your pattern list.
  10059.  
  10060. Whether EOS succeeds or fails, it does *not* advance the match cursor.
  10061.  
  10062. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10063.         macro to obtain the external declaration for this function).
  10064.  
  10065. Routine:  ARB
  10066. -------------
  10067.  
  10068. Category:             Pattern Matching Primitive
  10069. Author:              Randall Hyde
  10070.  
  10071. Registers on Entry:   N/A
  10072. Registers on return:  N/A
  10073. Flags affected:          N/A
  10074.  
  10075. Example of Usage:
  10076.  
  10077.     (Note:     Generally, ARB is only invoked in a pattern data struct-
  10078.         ure.  You would not normally call this code directly from your
  10079.         program [though it is possible, see the source listings for
  10080.         details].)
  10081.  
  10082.     ARBexample    pattern    <ARB>
  10083.  
  10084. Description:
  10085.  
  10086. ARB matches an arbitrary number of characters in a string (up to EOS).
  10087. It always succeeds.
  10088.  
  10089. SNOBOL4+ users- Stdlib's ARB function isn't exactly like SNOBOL4's.  This
  10090. ARB function uses a "greedy" algorithm.  It immediately grabs as many char-
  10091. acters as it can.  If there is a pattern following ARB (and there generally
  10092. is) backtracking *will* occur.  If you want an ARB operation which uses a
  10093. "shy" matching algorithm, take a look at the "MatchToPat" function.
  10094.  
  10095. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10096.         macro to obtain the external declaration for this function).
  10097.  
  10098. Routine:  ARBNUM
  10099. ----------------
  10100.  
  10101. Category:             Pattern Matching Primitive
  10102. Author:              Randall Hyde
  10103.  
  10104. Registers on Entry:   N/A
  10105. Registers on return:  N/A
  10106. Flags affected:          N/A
  10107.  
  10108. Example of Usage:
  10109.  
  10110.     (Note:     Generally, ARBNUM is only invoked in a pattern data struct-
  10111.         ure.  You would not normally call this code directly from your
  10112.         program [though it is possible, see the source listings for
  10113.         details].)
  10114.  
  10115.     ANexample    pattern    <ARBNUM, SomePattern>
  10116.     SomePattern    pattern    <some_other_pattern....>
  10117.  
  10118. Description:
  10119.  
  10120. ARBNUM matches zero or more occurrences of the pattern specified by the
  10121. "MatchParm" pattern.  It always succeeds and leaves the match cursor pointing
  10122. beyond the last character matched in the source string.  If it matches zero
  10123. occurrences of the specified pattern, it still succeeds and returns the
  10124. match cursor unchanged.
  10125.  
  10126. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10127.         macro to obtain the external declaration for this function).
  10128.  
  10129. Routine:  Skip
  10130. --------------
  10131.  
  10132. Category:             Pattern Matching Primitive
  10133. Author:              Randall Hyde
  10134.  
  10135. Registers on Entry:   N/A
  10136. Registers on return:  N/A
  10137. Flags affected:          N/A
  10138.  
  10139. Example of Usage:
  10140.  
  10141.     (Note:     Generally, Skip is only invoked in a pattern data struct-
  10142.         ure.  You would not normally call this code directly from your
  10143.         program [though it is possible, see the source listings for
  10144.         details].)
  10145.  
  10146.     Sexample    pattern    <Skip, 5, 0, NextPat>
  10147.  
  10148. Description:
  10149.  
  10150. Skip matches (skips over) the next "n" characters in the source string.
  10151. "n" is the L.O. word of the "MatchParm" parameter.
  10152.  
  10153. Skip succeeds if there were at least "n" characters in the string.  It fails
  10154. if there were less than "n" characters in the string.  If you want Skip to
  10155. succeed even if there are less than "n" characters in the string you can
  10156. use ARB as the alternate pattern for Skip:
  10157.  
  10158.     SARBexample    pattern    <Skip, 5, 0, ArbPat>
  10159.     ARBPat        pattern    <ARB>
  10160.  
  10161. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10162.         macro to obtain the external declaration for this function).
  10163.  
  10164. Routine:  POS
  10165. -------------
  10166.  
  10167. Category:             Pattern Matching Primitive
  10168. Author:              Randall Hyde
  10169.  
  10170. Registers on Entry:   N/A
  10171. Registers on return:  N/A
  10172. Flags affected:          N/A
  10173.  
  10174. Example of Usage:
  10175.  
  10176.     (Note:     Generally, POS is only invoked in a pattern data struct-
  10177.         ure.  You would not normally call this code directly from your
  10178.         program [though it is possible, see the source listings for
  10179.         details].)
  10180.  
  10181.     Pexample    pattern    <POS, 5, 0, NextPat>
  10182.  
  10183. Description:
  10184.  
  10185. POS (position) succeeds if the match cursor is currently at the location
  10186. specified by the "MatchParm" parameter.  It fails otherwise.  Note: the
  10187. first character in the source string is at position zero.
  10188.  
  10189. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10190.         macro to obtain the external declaration for this function).
  10191.  
  10192. Routine:  RPOS
  10193. --------------
  10194.  
  10195. Category:             Pattern Matching Primitive
  10196. Author:              Randall Hyde
  10197.  
  10198. Registers on Entry:   N/A
  10199. Registers on return:  N/A
  10200. Flags affected:          N/A
  10201.  
  10202. Example of Usage:
  10203.  
  10204.     (Note:     Generally, RPOS is only invoked in a pattern data struct-
  10205.         ure.  You would not normally call this code directly from your
  10206.         program [though it is possible, see the source listings for
  10207.         details].)
  10208.  
  10209.     RPexample    pattern    <RPOS, 5, 0, NextPat>
  10210.  
  10211. Description:
  10212.  
  10213. RPOS (position) succeeds if the match cursor is currently at the specified
  10214. location *from the end of the string*.  The last character in the string is
  10215. RPOS one (EOS is at position zero).
  10216.  
  10217. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10218.         macro to obtain the external declaration for this function).
  10219.  
  10220. Routine:  GotoPOS
  10221. -----------------
  10222.  
  10223. Category:             Pattern Matching Primitive
  10224. Author:              Randall Hyde
  10225.  
  10226. Registers on Entry:   N/A
  10227. Registers on return:  N/A
  10228. Flags affected:          N/A
  10229.  
  10230. Example of Usage:
  10231.  
  10232.     (Note:     Generally, GotoPOS is only invoked in a pattern data struct-
  10233.         ure.  You would not normally call this code directly from your
  10234.         program [though it is possible, see the source listings for
  10235.         details].)
  10236.  
  10237.     GPexample    pattern    <GotoPOS, 5, 0, NextPat>
  10238.  
  10239. Description:
  10240.  
  10241. GotoPos moves the match cursor *forward* to the specified position.  It fails
  10242. if that position does not exist in the string or if you attempt to move the
  10243. match cursor backwards in the string.
  10244.  
  10245. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10246.         macro to obtain the external declaration for this function).
  10247.  
  10248. Routine:  RGotoPOS
  10249. -----------------
  10250.  
  10251. Category:             Pattern Matching Primitive
  10252. Author:              Randall Hyde
  10253.  
  10254. Registers on Entry:   N/A
  10255. Registers on return:  N/A
  10256. Flags affected:          N/A
  10257.  
  10258. Example of Usage:
  10259.  
  10260.     (Note:     Generally, RGotoPOS is only invoked in a pattern data struct-
  10261.         ure.  You would not normally call this code directly from your
  10262.         program [though it is possible, see the source listings for
  10263.         details].)
  10264.  
  10265.     RGPexample    pattern    <RGotoPOS, 5, 0, NextPat>
  10266.  
  10267. Description:
  10268.  
  10269. RGotoPos moves the match cursor *forward* in the string to the point specified
  10270. by the "MatchParm" parameter.  This value is the position in the string from
  10271. the *end* of the string.  This function fails if you attempt to move the
  10272. match cursor backwards in the string or if the position does not exist in
  10273. the string.
  10274.  
  10275. Include:    stdlib.a or patterns.a (and then invoke the "matchfuncs"
  10276.         macro to obtain the external declaration for this function).
  10277.  
  10278.